관리 메뉴

도드넷

JAVASCRIPT#76 - 횡스크롤 101 본문

창고/JS KING 포니 [중단]

JAVASCRIPT#76 - 횡스크롤 101

도드! 2016. 8. 1. 02:09
반응형



I can only hope, i can only prey that someday in some point of my life, i finally meet you and we fall in love. 


JAVASCRIPT#76 - 횡스크롤 101 모든 함수정리


1. 스프라이트 추가하기


1.  스프라이트 프래그먼트 선언.


gf.spriteFragment = $("<div class='gf_sprite' style='position: absolute; overflow: hidden;'></div>");



2. 스프라이트 DOM 객체 생성함수. 


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. options를 데이터로 가지는 스프라이트 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. 만든 DOM 객체를 실제로 스크린에 추가.


    parent.append(sprite);


2-4. DOM 객체를 반환.


    return sprite;

}



2. 애니메이션 셋팅 시스템


1. 프레임 설정 함수.


gf.setFrame = function(div, animation) {
    div.css("backgroundPosition", "-" + (animation.currentFrame * animation.width + animation.offset) + "px 0px");
}


2. 애니메이션 객체 정의.


gf.animation = function(options)
{

2-1. 전달된 옵션값을 바탕으로 애니메이션 객체의 프로퍼티를 설정.


    var defaultValues = {
        url : false,
        width : 64,
        numberOfFrames : 1,
        currentFrame : 0,
        rate : 1,
        offset: 0
    }
    $.extend(this, defaultValues, options);


2-2. 애니메이션의 레이트값을 기본 반복문 레이트값에 의해 설정.


    if(options.rate){
        // normalize the animation rate
        this.rate = Math.round(this.rate / gf.baseRate);
    }


2-3. 프리로드에 애니메이션에 사용될 이미지 주소 저장.


    if(this.url){
        gf.addImage(this.url);
    }

}



3. 애니메이션 집합 설정.


gf.animations = [];


4. 애니메이션 설정 함수 정의.


gf.setAnimation = function(div, animation, loop)
{

4-1. 해당 div를 위한 복사_제 2차 애니메이션 객체 선언.

 

   var animate = {
        animation: $.extend({}, animation), // extend로 전달하게 될경우 복사해서 따로 만드는게 됨
        div: div,
        loop: loop,
        counter: 0
    }



4-2. 해당 DOM의 배경 이미지를 전달된 애니메이션 객체의 url로 설정.


    if(animation.url){
        div.css("backgroundImage","url('"+animation.url+"')");
    }



   

    4-3. 재생되고 있는 애니메이션이 있나없나 검사.


    var divFound = false;


4-4. 만약 입력받은 div의 div를 가진 애니메이션이 있다면 해당 애니메이션을 입력받은 애니메이션으로 변경.


    for (var i = 0; i < gf.animations.length; i++)

{

if(gf.animations[i].div.is(div)// 참고로 여기서 is 는 == 하고 같음.

{
    divFound = true;
    gf.animations[i] = animate;
}

}


4-5. 찾을수없다면 해당 애니메이션을 div의 애니메이션으로 새로등록

   

if(!divFound) {

gf.animations.push(animate);
   

}


5. 주 반복문


gf.refreshGame = function (){
   

    5-1. 끝난 애니메이션 배열 정의 


    var finishedAnimations = [];
   

5-2. 애니메이션 재생 반복문 (1반복 당 한 프레임씩 진행시킴)


    for (var i=0; i < gf.animations.length; i++) {
       
        var animate = gf.animations[i];
       
        animate.counter++;
        if (animate.counter == animate.animation.rate) {
            animate.counter = 0;
            animate.animation.currentFrame++;
            if(!animate.loop && animate.animation.currentFrame > animate.animation.numberOfFrames){
                finishedAnimations.push(i);
            } else {
                animate.animation.currentFrame %= animate.animation.numberOfFrames;
                gf.setFrame(animate.div, animate.animation);
            }
        }
    }


5-3. 끝난 애니메이션은 배열에서 제외함으로 애니메이션 종료.


    for(var i=0; i < finishedAnimations.length; i++){
        gf.animations.splice(finishedAnimations[i], 1);
    }
   

?. 종합 반복문 (time 관련해서 지워도 상관없음)


    // execute the callbacks
    for (var i=0; i < gf.callbacks.length; i++) {
        var call  = gf.callbacks[i];
       
        call.counter++;
        if (call.counter == call.rate) {
            var currentTime = (new Date()).getTime();
            call.counter = 0;
            call.callback(currentTime - gf.time);
        }
    }
    gf.time = (new Date()).getTime();
}



/// DEMO :

var playerAnim = {
        stand: new gf.animation({
            url: "Images/player.png",
            offset: 75
        }),
        walk:  new gf.animation({
            url:    "Images/player.png",
            offset: 150,
            width:  75,
            numberOfFrames: 10,
            rate: 90
        }),
        jump:  new gf.animation({
            url: "Images/player.png",
            offset: 900
        })
    };


gf.setAnimation(this.div, playerAnim.walk, true);




3. DOM 포지셔닝 시스템


gf.x = function(div,position) {
    if(position) {
        div.css("left", position);
        div.data("gf").x = position;
    } else {
        return div.data("gf").x;
    }
}

gf.y = function(div,position) {
    if(position) {
        div.css("top", position);
        div.data("gf").y = position;
    } else {
        return div.data("gf").y;
    }
}


gf.x(this.div, newX);
gf.y(this.div, newY);



4. 타일 시스템


1. 타일 애니메이션 배열 정의


var tiles =
    [
        new gf.animation({
            url: "Images/tiles.png"
        }),
        new gf.animation({
            url: "Images/tiles.png",
            offset: 70
        }),
        new gf.animation({
            url: "Images/tiles.png",
            offset: 140
        }),
        new gf.animation({
            url: "Images/tiles.png",
            offset: 210
        }),
        new gf.animation({
            url: "Images/tiles.png",
            offset: 280
        }),
        new gf.animation({
            url: "Images/tiles.png",
            offset: 350
        }),
        new gf.animation({
            url: "Images/tiles.png",
            offset: 420
        }),
    ];


2. 레벨 구성용 2차 배열 정의


var level = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
             [0, 0, 0, 2, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7],
             [5, 5, 5, 5, 5, 6, 6, 5, 5, 5, 5, 6, 6, 6, 5, 5, 5, 6, 6, 5, 5, 5, 5, 5, 5, 5, 6, 6, 5, 5, 5, 5, 6, 6, 6, 5, 5, 5, 6, 6, 5, 5]];


3. 타일맵 DOM 프래그맨트 생성    


gf.tilemapFragment = $("<div class='gf_tilemap' style='position: absolute'></div>");


4. 타일맵과 타일 객체 생성함수


gf.addTilemap = function(parent, divId, options)
{

4-1. 타일맵 객체의 옵션 설정


    var options = $.extend({
        x: 0,
        y: 0,
        tileWidth: 64,
        tileHeight: 64,
        width: 0,
        height: 0,
        map: [],
        animations: []
    }, options);
   
    4-2. 타일을 담을 타일맵 객체 생성

  
    var tilemap = gf.tilemapFragment.clone().attr("id",divId).data("gf",options);


4-3. 타일 생성


    for (var i=0; i < options.height; i++){

        for(var j=0; j < options.width; j++) {


4-3-1. 타일 인덱스 값 구하기


            var animationIndex = options.map[i][j];
           

4-3-2. 타일 인덱스 값이 0 보다 크면 타일 생성


            if(animationIndex > 0){


4-3-2-1. 타일 옵션 설정


                var tileOptions = {
                    x: options.x + j*options.tileWidth,
                    y: options.y + i*options.tileHeight,
                    width: options.tileWidth,
                    height: options.tileHeight
                }


4-3-2-2. i행 j열에 해당하는 타일 생성


                var tile = gf.spriteFragment.clone().css({
                    left:   tileOptions.x,
                    top:    tileOptions.y,
                    width:  tileOptions.width,
                    height: tileOptions.height}
                ).addClass("gf_line_"+i).addClass("gf_column_"+j).data("gf", tileOptions);

               

                4-3-2-3. 해당 타일의 애니메이션 설정

 

                gf.setAnimation(tile, options.animations[animationIndex-1]);
               

                4-3-2-4. 해당 타일을 타일맵에 추가


                tilemap.append(tile);
            }
        }
    }


4-4. 타일맵을 부모 DOM에 추가


    parent.append(tilemap);

   

    4-5. 타일맵 반환   


    return tilemap;
}



5. 타일 - 물체 충돌 시스템


1. 두 선분의 충돌 위치를 반환하는 함수


gf.intersect = function(a1,a2,b1,b2){
    var i1 = Math.min(Math.max(a1, b1), a2);
    var i2 = Math.max(Math.min(a2, b2), a1);
    return [i1, i2];
}


2. 타일맵과 물체의 충돌 위치를 인덱스로 전환해서 반환하는 인덱스 반환 함수


gf.tilemapBox = function(tilemapOptions, boxOptions){


    2-1. 타일맵의 가로, 세로

   

    var tmX  = tilemapOptions.x;
    var tmXW = tilemapOptions.x + tilemapOptions.width * tilemapOptions.tileWidth;
    var tmY  = tilemapOptions.y;
    var tmYH = tilemapOptions.y + tilemapOptions.height * tilemapOptions.tileHeight;
   

    2-2. 물체의 가로, 세로


    var bX  = boxOptions.x;
    var bXW = boxOptions.x + boxOptions.width;
    var bY  = boxOptions.y;
    var bYH = boxOptions.y + boxOptions.height;
   

2-3. 타일맵과 물체의 충돌 위치를 구함.


    var x = gf.intersect(tmX,tmXW, bX, bXW);
    var y = gf.intersect(tmY, tmYH, bY, bYH);
   

    2-4. 충돌위치를 인덱스로 전환


    return {
        x1: Math.floor((x[0] - 0) / tilemapOptions.tileWidth),
        y1: Math.floor((y[0] - 0) / tilemapOptions.tileHeight),
        x2: Math.ceil((x[1] - 0) / tilemapOptions.tileWidth),
        y2: Math.ceil((y[1] - 0) / tilemapOptions.tileHeight)
    }
}


3. 타일 충돌 감지 :: 반환된 인덱스를 바탕으로 어떤 타일이 충돌했는지 알아내서 배열로 반환함.


gf.tilemapCollide = function(tilemap, box)
{

    3-1. 타일맵 데이터 가져오기


    var options = tilemap.data("gf");


3-2. 타일맵과 물체의 충돌위치 인덱스 구하기 


    var collisionBox = gf.tilemapBox(options, box);


3-3. 겹친 타일의 div를 저장할 배열 선언


    var divs = [];


3-4. 충돌위치 인덱스 바탕으로 해당 타일과 타일의 인덱스 구하기   


    for (var i = collisionBox.y1; i < collisionBox.y2; i++){
        for (var j = collisionBox.x1; j < collisionBox.x2; j++){
       
            var index = options.map[i][j];
            if( index > 0 && index < 6 ){
                divs.push(tilemap.find(".gf_line_"+i+".gf_column_"+j)); // 타일맵이라는 객체중 ".gf_line_"+i+".gf_column_"+j"에 해당하는 클래스를 가진 객체를 찾아서 divs에 저장함.
            }
            else
            {
                player.onTheGround = 0;
            }

        }
    }


3-5. 충돌한 타일 객체를 모은 divs 반환


    return divs;
}


4. 플레이어 객체 선언


var player = new (function()
{


        var acceleration = 9;
        var speed = 20;
        var status = "stand";
        var horizontalMove = 0;
        var onTheGround = 0;
       

4-1. 플레이어 위치 갱신 함수 (반복됨)


        this.update = function ()
        {
            var delta = 30;


            speed = Math.min(100,Math.max(-100, speed + acceleration * delta / 100.0));



            4-1-1. 새 위치 설정용 변수들 설정. 

         
            var newY = gf.y(this.div) + speed * delta / 100.0;
            var newX = gf.x(this.div) + horizontalMove;
            var newW = gf.width(this.div);
            var newH = gf.height(this.div);

          

              4-1-2. 충돌한 타일을 구하기위해 함수호출해서 배열로써 저장.

                                
            var collisions = gf.tilemapCollide(tilemap, {x: newX, y: newY, width: newW, height: newH});
           

4-1-3. 충돌 반응/처리용 특수 반복문


            var i = 0;
            while (i < collisions.length > 0)

{


                4-1-3-1. 충돌한 타일객체를 저장


                var collision = collisions[i];
                i++;


4-1-3-2. 충돌한 타일객체를 상자형 4포인트 객체로 만듬


                var collisionBox = {
                    x1: gf.x(collision),
                    y1: gf.y(collision),
                    x2: gf.x(collision) + gf.width(collision),
                    y2: gf.y(collision) + gf.height(collision)
                };

 

                4-1-3-3. 방금만든 타일 상자와 플레이어 캐릭터간에 충돌 지점을 구함

                

                var x = gf.intersect(newX, newX + newW, collisionBox.x1,collisionBox.x2);
                var y = gf.intersect(newY, newY + newH, collisionBox.y1,collisionBox.y2);
               

4-1-3-4. 진입 방향에 따라 차잇값을 따로 구하게함.


                var diffx = (x[0] == newX)? x[0]-x[1] : x[1]-x[0];
                var diffy = (y[0] == newY)? y[0]-y[1] : y[1]-y[0];


                4-1-3-5. Y충돌 인지 X충돌 인지 가려서 각기다른 차잇값을 빼줌으로 겹치지않게 해줌. 

               

                if (Math.abs(diffx) > Math.abs(diffy)){
                    // displace along the y axis
                    if(y[0] == newY)
                    {
                      
                    }
                    else
                    {
                      
                    }

                    this.onTheGround = 1;
                    newY -= diffy;
                    speed = 0;

                    if(status=="jump" && diffy > 0)
                    {
                        status="stand";
                        gf.setAnimation(this.div, playerAnim.stand);
                    }
                    
                }
                else
                {                 
                    if(x[0] == newX)
                    {
                      
                    }
                    else
                    {
                       
                    }
                    newX -= diffx;
                }
            }
           

5. 플레이어 위치설정           


            gf.x(this.div, newX);
            gf.y(this.div, newY);


            6. 1 업데이트당 좌우로 움직이는 양 제한. 무한 이속 스택킹 방지. 


            horizontalMove = 0;
        };
       
        this.left = function ()
        {
            switch (status)
            {
                case "stand":
                    gf.setAnimation(this.div, playerAnim.walk, true);
                    status = "walk";
                    horizontalMove -= 7;
                    break;
                case "jump":
                    horizontalMove -= 5;
                    break;
                case "walk":
                    horizontalMove -= 7;
                    break;
            }
            gf.transform(this.div, {flipH: true});
        };
       
        this.right = function ()
        {
            switch (status)
            {
                case "stand":
                    gf.setAnimation(this.div, playerAnim.walk, true);
                    status = "walk";
                    horizontalMove += 7;
                    break;
                case "jump":
                    horizontalMove += 5;
                    break;
                case "walk":
                    horizontalMove += 7;
                    break;
            }
            gf.transform(this.div, {flipH: false});
        };
       
        this.jump  = function ()
        {
            switch (status)
            {
               
                case "stand":
                case "walk":
                    status = "jump";
                    speed = -60;
                    gf.setAnimation(this.div, playerAnim.jump);
                    this.onTheGround = 0;
                    break;
            }
        };
       
        this.idle  = function (){
            switch (status)
            {
                case "walk":
                    status = "stand";
                    gf.setAnimation(this.div, playerAnim.stand);
                    break;
            }
        };
});



6. 중력 구현


var player = new (function()
{

1. 플레이어 객체의 프로퍼티들


        var acceleration = 9;
        var speed = 20;
        var status = "stand";
        var horizontalMove = 0;
        var onTheGround = 0;
       

2. 플레이어 위치 갱신함수


        this.update = function ()
        {

            2-1. 조절값 정의


            var delta = 30;


            2-2. 상하 움직임용 속도를 -100~100 범위에서 일정히 지속적으로 증가시킴 (중력)


            speed = Math.min(100,Math.max(-100, speed + acceleration * delta / 100.0));


2-3. 새 위치 설정 


            var newY = gf.y(this.div) + speed * delta / 100.0;
            var newX = gf.x(this.div) + horizontalMove;
            var newW = gf.width(this.div);
            var newH = gf.height(this.div);           
           
            // COLLISION PART2
            var collisions = gf.tilemapCollide(tilemap, {x: newX, y: newY, width: newW, height: newH});
           
            var i = 0;
            while (i < collisions.length > 0)
            {
                var collision = collisions[i];
                i++;
                var collisionBox = {
                    x1: gf.x(collision),
                    y1: gf.y(collision),
                    x2: gf.x(collision) + gf.width(collision),
                    y2: gf.y(collision) + gf.height(collision)
                };
 
                var x = gf.intersect(newX, newX + newW, collisionBox.x1,collisionBox.x2);
                var y = gf.intersect(newY, newY + newH, collisionBox.y1,collisionBox.y2);
               
                var diffx = (x[0] == newX)? x[0]-x[1] : x[1]-x[0];
                var diffy = (y[0] == newY)? y[0]-y[1] : y[1]-y[0];

                if (Math.abs(diffx) > Math.abs(diffy)){
                    // displace along the y axis
                    if(y[0] == newY)
                    {
                      
                    }
                    else
                    {
                      
                    }

                    this.onTheGround = 1;
                    newY -= diffy;
                    speed = 0;

                    if(status=="jump" && diffy > 0)
                    {
                        status="stand";
                        gf.setAnimation(this.div, playerAnim.stand);
                    }
                    
                }
                else
                {                 
                    if(x[0] == newX)
                    {
                      
                    }
                    else
                    {
                       
                    }
                    newX -= diffx;
                }
                //collisions = gf.tilemapCollide(tilemap, {x: newX, y: newY, width: newW, height: newH});
            }


            2-4. 플레이어 객체 위치설정.

           
            gf.x(this.div, newX);
            gf.y(this.div, newY);


            2-5. 좌우 속도 제한, 스택킹 방지. 


            horizontalMove = 0;
        };
       
        this.left = function ()
        {
            switch (status)
            {
                case "stand":
                    gf.setAnimation(this.div, playerAnim.walk, true);
                    status = "walk";
                    horizontalMove -= 7;
                    break;
                case "jump":
                    horizontalMove -= 5;
                    break;
                case "walk":
                    horizontalMove -= 7;
                    break;
            }
            gf.transform(this.div, {flipH: true});
        };
       
        this.right = function ()
        {
            switch (status)
            {
                case "stand":
                    gf.setAnimation(this.div, playerAnim.walk, true);
                    status = "walk";
                    horizontalMove += 7;
                    break;
                case "jump":
                    horizontalMove += 5;
                    break;
                case "walk":
                    horizontalMove += 7;
                    break;
            }
            gf.transform(this.div, {flipH: false});
        };
       
        this.jump  = function ()
        {
            switch (status)
            {
               
                case "stand":
                case "walk":
                    status = "jump";
                    speed = -60;
                    gf.setAnimation(this.div, playerAnim.jump);
                    this.onTheGround = 0;
                    break;
            }
        };
       
        this.idle  = function (){
            switch (status)
            {
                case "walk":
                    status = "stand";
                    gf.setAnimation(this.div, playerAnim.stand);
                    break;
            }
        };
});



7. 플레이어 컨트롤


1. 키값 저장할 배열 선언


gf.keyboard = [];


2. 키 이벤트를 통해서 키값 설정


$(document).keydown(function(event){
    gf.keyboard[event.keyCode] = true;
});
$(document).keyup(function(event){
    gf.keyboard[event.keyCode] = false;
});


3. 플레이어 객체 전용 이동함수 정의


var player = new (function()
{
        var acceleration = 9;
        var speed = 20;
        var status = "stand";
        var horizontalMove = 0;
        var onTheGround = 0;
       
        this.update = function ()
        {
            var delta = 30;
            speed = Math.min(100,Math.max(-100, speed + acceleration * delta / 100.0));
            var newY = gf.y(this.div) + speed * delta / 100.0;
            var newX = gf.x(this.div) + horizontalMove;
            var newW = gf.width(this.div);
            var newH = gf.height(this.div);           
           
            // COLLISION PART2
            var collisions = gf.tilemapCollide(tilemap, {x: newX, y: newY, width: newW, height: newH});
           
           

            var i = 0;
            while (i < collisions.length > 0)
            {
                var collision = collisions[i];
                i++;
                var collisionBox = {
                    x1: gf.x(collision),
                    y1: gf.y(collision),
                    x2: gf.x(collision) + gf.width(collision),
                    y2: gf.y(collision) + gf.height(collision)
                };
 
                var x = gf.intersect(newX, newX + newW, collisionBox.x1,collisionBox.x2);
                var y = gf.intersect(newY, newY + newH, collisionBox.y1,collisionBox.y2);
               
                var diffx = (x[0] == newX)? x[0]-x[1] : x[1]-x[0];
                var diffy = (y[0] == newY)? y[0]-y[1] : y[1]-y[0];

                if (Math.abs(diffx) > Math.abs(diffy)){
                    // displace along the y axis
                    if(y[0] == newY)
                    {
                      
                    }
                    else
                    {
                      
                    }

                    this.onTheGround = 1;
                    newY -= diffy;
                    speed = 0;

                    if(status=="jump" && diffy > 0)
                    {
                        status="stand";
                        gf.setAnimation(this.div, playerAnim.stand);
                    }
                    
                }
                else
                {                 
                    if(x[0] == newX)
                    {
                      
                    }
                    else
                    {
                       
                    }
                    newX -= diffx;
                }
                //collisions = gf.tilemapCollide(tilemap, {x: newX, y: newY, width: newW, height: newH});
            }

            gf.x(this.div, newX);
            gf.y(this.div, newY);

            horizontalMove = 0;
        };
       

3-1. 좌이동 함수


        this.left = function ()
        {
            switch (status)
            {
                case "stand":
                    gf.setAnimation(this.div, playerAnim.walk, true);
                    status = "walk";
                    horizontalMove -= 7;
                    break;
                case "jump":
                    horizontalMove -= 5;
                    break;
                case "walk":
                    horizontalMove -= 7;
                    break;
            }
            gf.transform(this.div, {flipH: true});
        };
       

3-2. 우이동 함수


        this.right = function ()
        {
            switch (status)
            {
                case "stand":
                    gf.setAnimation(this.div, playerAnim.walk, true);
                    status = "walk";
                    horizontalMove += 7;
                    break;
                case "jump":
                    horizontalMove += 5;
                    break;
                case "walk":
                    horizontalMove += 7;
                    break;
            }
            gf.transform(this.div, {flipH: false});
        };

       

3-3. 점프 함수


        this.jump  = function ()
        {
            switch (status)
            {
               
                case "stand":
                case "walk":
                    status = "jump";
                    speed = -60;
                    gf.setAnimation(this.div, playerAnim.jump);
                    this.onTheGround = 0;
                    break;
            }
        };
       

3-4. 아이들 함수


        this.idle  = function (){
            switch (status)
            {
                case "walk":
                    status = "stand";
                    gf.setAnimation(this.div, playerAnim.stand);
                    break;
            }
        };
});


4. 주 반복문  


var gameLoop = function()

{
       

4-1. 키가 눌리지않은 상황에서 기본적으로 플레이어는 아이들(idle) 상태여야함.


        var idle = true;


4-2. 키 바인딩


        if(gf.keyboard[37]){
            player.left();
            idle = false;
        }
        if(gf.keyboard[38] && player.onTheGround == 1){
             player.jump();
            idle = false;
        }
        if(gf.keyboard[39]){
            player.right();
            idle = false;
        }


4-3. 키가 눌리지않아 아이들이 유지될경우 idle 함수 실행


        if(idle){
            player.idle();
        }


4-4. 플레이어 위치 갱신 함수 실행

       
        player.update();

        for (var i = 0; i < enemies.length; i++){
            enemies[i].update();
            if (gf.spriteCollide(player.div, enemies[i].div)){
                enemies[i].kill();
            }
        }
       
        var playerPos = gf.x(player.div);
        if(playerPos > 200) {
            gf.x(group, 200 - playerPos);
            $("#backgroundFront").css("background-position",""+(200 * 0.66 - playerPos * 0.66)+"px 0px");
            $("#backgroundBack").css("background-position",""+(200 * 0.33 - playerPos * 0.33)+"px 0px");
        }
};






8. 적 생성


1. 적 모음집 정의


var enemies = [];


2. 슬라임 객체 생성함수


var Slime = function()

{      

2-1. 슬라임 객체의 여러가지 프로퍼티를 설정하는 함수정의


        this.init = function(div, x1, x2, anim) {
            this.div = div;
            this.x1 = x1;
            this.x2 = x2;
            this.anim = anim;
            this.direction = 1;
            this.speed     = 5;
            this.dead      = false;
           
            gf.transform(div, {flipH: true});
            gf.setAnimation(div, anim.walk);
        };


2-2. 슬라임 객체 위치갱신 함수

       
        this.update = function(){
            if(this.dead){
                this.dies();
            } else {
                var position = gf.x(this.div);
                if (position < this.x1){
                    this.direction = 1;
                    gf.transform(this.div, {flipH: true});
                }
                if (position > this.x2){
                    this.direction = -1;
                    gf.transform(this.div, {flipH: false});
                }
                gf.x(this.div, gf.x(this.div) + this.direction * this.speed);
            }
        }


2-3. 슬라임 킬(죽이는) 함수 정의


        this.kill = function(){
            this.dead = true;
            gf.setAnimation(this.div, this.anim.dead);
        }


2-4. 죽음이면 발동하는 함수 정의


        this.dies = function(){}
    };


3. 플라이 생성함수 정의


var Fly = function() {}


3-1. 슬라임 함수를 복사해서 플라이함수 재정의


Fly.prototype = new Slime();


3-2. 플라이용 사망 함수 재정의


Fly.prototype.dies = function(){
    gf.y(this.div, gf.y(this.div) + 5);
}


4. 주 반복문


var gameLoop = function() {
       
        var idle = true;
        if(gf.keyboard[37]){ //left arrow
              player.left();
            idle = false;
        }
        if(gf.keyboard[38] && player.onTheGround == 1){ //up arrow
             player.jump();
            idle = false;
        }
        if(gf.keyboard[39]){ //right arrow
            player.right();
            idle = false;
        }
        if(idle){
            player.idle();
        }
       
        player.update();


        4-1. 적 그룹으로 반복문 실행


        for (var i = 0; i < enemies.length; i++){

 

           4-1-1. 적 객체 위치갱신

 
            enemies[i].update();


           4-1-2. 적과 플레이어가 충돌시 해당 적 객체 킬함수 작동.


            if (gf.spriteCollide(player.div, enemies[i].div)){
                enemies[i].kill();
            }
        }
       
        var playerPos = gf.x(player.div);
        if(playerPos > 200) {
            gf.x(group, 200 - playerPos);
            $("#backgroundFront").css("background-position",""+(200 * 0.66 - playerPos * 0.66)+"px 0px");
            $("#backgroundBack").css("background-position",""+(200 * 0.33 - playerPos * 0.33)+"px 0px");
        }
    };
   
    gf.addCallback(gameLoop, 30);




9. 화면, 맵 이동 구현


var gameLoop = function() {
       
        var idle = true;
        if(gf.keyboard[37]){ //left arrow
              player.left();
            idle = false;
        }
        if(gf.keyboard[38] && player.onTheGround == 1){ //up arrow
             player.jump();
            idle = false;
        }
        if(gf.keyboard[39]){ //right arrow
            player.right();
            idle = false;
        }
        if(idle){
            player.idle();
        }
       
        player.update();

        for (var i = 0; i < enemies.length; i++){
            enemies[i].update();
            if (gf.spriteCollide(player.div, enemies[i].div)){
                enemies[i].kill();
            }
        }
       

       1. 플레이어 객체 위치 저장


        var playerPos = gf.x(player.div);


        2. 플레이어 객체 위치가 200 초과할시 뒷배경과 그룹에 속하는 모든 DOM 요소를 반대방향으로 이동


        if(playerPos > 200) {
            gf.x(group, 200 - playerPos);
            $("#backgroundFront").css("background-position",""+(200 * 0.66 - playerPos * 0.66)+"px 0px");
            $("#backgroundBack").css("background-position",""+(200 * 0.33 - playerPos * 0.33)+"px 0px");
        }
    };
   
    gf.addCallback(gameLoop, 30);



10. 이미지 프리로드와 초기화 함수


0. 프리로드용 배열과 이미지 추가 함수정의


gf.imagesToPreload = [];

gf.addImage = function(url)
{
    if ($.inArray(url, gf.imagesToPreload) < 0)
    {
        gf.imagesToPreload.push();
    }
    gf.imagesToPreload.push(url);
}


1. 게임시작 함수


gf.startGame = function(endCallback, progressCallback)
{


    1-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];
    }
   

1-2. 이미지 프리로드 검사용 반복문 설정


    var preloadingPoller = setInterval(function() {
        var counter = 0;
        var total = gf.imagesToPreload.length;
        for (var i = 0; i < total; i++) {
            if (images[i].complete) {
                counter++;
            }
        }


1-2-1. 이미지 로드가 끝나면 반복문을 마치고 주 반복문을 실행시킴


        if (counter == total) {
            clearInterval(preloadingPoller);
            endCallback()
            setInterval(gf.refreshGame, gf.baseRate);
            gf.time = (new Date()).getTime();
        } else {
            if (progressCallback) {
                count++;
                progressCallback((count / total) * 100);
            }
        }
    }, 100);
};


2. 초기화 함수


var initialize = function()
{


2-1. 스프라이트 객체, 그룹, 타일, 플레이어, 슬라임, 플라이 생성하고 애니메이션 설정하고 씬에 추가


        $("#mygame").append("<div id='container' style='display: none; width: 640px; height: 480px;'>");
        container       = $("#container");
        backgroundBack  = gf.addSprite(container,"backgroundBack",{width: 640, height: 480});
        backgroundFront = gf.addSprite(container,"backgroundFront",{width: 640, height: 480});
        group           = gf.addGroup(container,"group");
        tilemap         = gf.addTilemap(group, "level", {tileWidth: 70, tileHeight: 70, width: 42, height: 7, map: level, animations: tiles});
        player.div      = gf.addSprite(group,"player",{width: 74, height: 93});
       
        var fly1   = new Fly();
        fly1.init(
            gf.addSprite(group,"fly1",{width: 69, height: 31, x: 280, y: 220}),
            280, 490,
            flyAnim
        );
        enemies.push(fly1);
       
        var slime1 = new Slime();
        slime1.init(
            gf.addSprite(group,"slime1",{width: 43, height: 28, x: 980, y: 392}),
            980, 1140,
            slimeAnim
        );
        enemies.push(slime1);
       
        var slime2 = new Slime();
        slime2.init(
            gf.addSprite(group,"slime2",{width: 43, height: 28, x: 1960, y: 392}),
            1960, 2200,
            slimeAnim
        );
        enemies.push(slime2);

        gf.setAnimation(player.div, playerAnim.stand);
        gf.setAnimation(backgroundBack, backgroundBackAnim);
        gf.setAnimation(backgroundFront, backgroundFrontAnim);
       
       
        container.css("display", "block");
}

gf.startGame(initialize);



11. 주 반복문


1. 콜백(추가 반복문) 배열 정의


gf.callbacks = [];


2. 콜백(추가 반복문)으로 추가하는 함수정의


gf.addCallback = function(callback, rate){
   

2-1. 콜백 배열에 해당 함수와 레이트, 카운터로 구성된  반복문 객체 넣기.


        gf.callbacks.push({
        callback: callback,
        rate: Math.round(rate / gf.baseRate),
        counter: 0
    });
}


3. 주 반복문 정의


gf.refreshGame = function (){
   
    var finishedAnimations = [];
   
    for (var i=0; i < gf.animations.length; i++) {
       
        var animate = gf.animations[i];
       
        animate.counter++;
        if (animate.counter == animate.animation.rate) {
            animate.counter = 0;
            animate.animation.currentFrame++;
            if(!animate.loop && animate.animation.currentFrame > animate.animation.numberOfFrames){
                finishedAnimations.push(i);
            } else {
                animate.animation.currentFrame %= animate.animation.numberOfFrames;
                gf.setFrame(animate.div, animate.animation);
            }
        }
    }
    for(var i=0; i < finishedAnimations.length; i++){
        gf.animations.splice(finishedAnimations[i], 1);
    }
   


    3-1. 콜백(추가 반복문) 제어함수

   
    for (var i=0; i < gf.callbacks.length; i++) {


3-1-1. 현재 인덱스에 해당하는 콜백을 콜에 넣어서 설정

       

        var call = gf.callbacks[i];
       

        3-1-2. 현재 콜백의 카운터 값 증가


        call.counter++;


3-1-3. 만약 현재 콜백의 카운터값이 레이트와 동일할경우 콜백 실행


        if (call.counter == call.rate) {
            call.counter = 0;
            call.callback();
        }
    }  
}



4. 제 1 반복문 gameLoop 정의


var gameLoop = function() {
       
        var idle = true;
        if(gf.keyboard[37]){ //left arrow
              player.left();
            idle = false;
        }
        if(gf.keyboard[38] && player.onTheGround == 1){ //up arrow
             player.jump();
            idle = false;
        }
        if(gf.keyboard[39]){ //right arrow
            player.right();
            idle = false;
        }
        if(idle){
            player.idle();
        }
       
        player.update();

        for (var i = 0; i < enemies.length; i++){
            enemies[i].update();
            if (gf.spriteCollide(player.div, enemies[i].div)){
                enemies[i].kill();
            }
        }
       
        var playerPos = gf.x(player.div);
        if(playerPos > 200) {
            gf.x(group, 200 - playerPos);
            $("#backgroundFront").css("background-position",""+(200 * 0.66 - playerPos * 0.66)+"px 0px");
            $("#backgroundBack").css("background-position",""+(200 * 0.33 - playerPos * 0.33)+"px 0px");
        }
    };


5. 제 1 반복문을 주 반복문에 추가


gf.addCallback(gameLoop, 30);






반응형
Comments