캐릭터가 올라갈 수 있는 움직이는 블록을 만들겠습니다. 다음같은 속성을 갖습니다.

  • 이동방향
  • 거리
  • 시간
  • 플레이어가 올라가면 움직이느냐?

움직이는 블록 게임 오브젝트 만들기

Assets>Images폴더내 block_move을 프로젝트 뷰에서 씬뷰로 배치해 게임 오브젝트를 만들고 이름은 MovingBlock으로 합니다.

인스펙트뷰에서 Layer를 Ground로 하고 Sprite Rendere의 Order in Layer의 값을  2로 설정하고 Box Collider 2D를 어태치합니다. 이동 블록은 물리동작을 따르지 않아 Rigidbody는 필요없습니다.

 

블록을 움직이는 스크립트 작성

MovingBlock 스크립트를 만들고 MovingBlock 게임오브젝트에 어태치해줍니다.

변수

public float moveX = 0.0f;          //X이동거리
public float moveY = 0.0f;          //Y이동거리
public float times = 0.0f;          //단방향 이동시간
public float weight = 0.0f;         //정지 시간
public bool isMoveWhenOn = false;   //올라 탓을 때 움직이기

public bool isCanMove = true;       //움직임
float perDX;                        //1프레임 당 X이동 값, 이동속도
float perDY;                        //1프레임 당 Y이동 값, 이동속도
Vector3 defPos;                     //초기 위치, 왕복시 돌아올 위치
bool isReverse = false;             //정방향 반대반향 여부

Start()

perDX = moveX / (1.0f / timestep * times);  //1 프레임의 X 이동 값 이다.

float timestep = Time.fixedDeltaTime; //1프레임에 이동하는 시간

1/timestep = 1초당 프레임수

moveX/프레임수 = 1초동안 인동할 때 한프레임당 이동거리

한프레임당 이동거리 / times = times초 이동시 한프레임 이동거리

결론은 perDX는 tiems초 동안 블록이 moveX거리를 이동할때 프레임당 이동거리이다. 간단한걸 엄청 복잡하게 써놨다.

그냥 perDX = moveX * Time.fixedDeltaTime * speed(1/ times)와 같다. ㅠㅠㅠ

만일 블록 특성이 isMoveWhenOn(올라타야 움직임) = true라면 isCanMove = false로 만들어 블록이 이동못하게 한다.

void Start(){
    defPos = transform.position;         //초기 위치
    float timestep = Time.fixedDeltaTime; //1프레임에 이동하는 시간 
    perDX = moveX / (1.0f / timestep * times);  //1 프레임의 X 이동 값
    perDY = moveY / (1.0f / timestep * times); //1 프레임의 Y 이동 값

    if (isMoveWhenOn){
        //처음엔 움직이지 않고 올라 타면 움직이기 시작
        isCanMove = false;
    }
}

FixedUpdate()

코드가 긴것 같은데 별것 없다. 위에서 정한 perDX값만큼 매 프레임 transform.Translate()만큼 움직여주면 된다. 그러다 moveX만큼 움직이거나 다시 원위치로 오면 잠시 쉬었다가 방향을 반전해 주면 된다.

 Vector3 v = new Vector3(perDX, perDY, defPos.z);
                transform.Translate(v);

원점에 도착하면 현재위치 transfor.position = defPos로 보정해줘 실수연산오차를 방지해준다.

private void FixedUpdate(){
        if (isCanMove) {
            //이동중
            float x = transform.position.x;
            float y = transform.position.y;
            bool endX = false;
            bool endY = false;
            if (isReverse){
                //반대 방향 이동
                //이동량이 양수고 이동 위치가 초기 위치보다 작거나
                //이동량이 음수고 이동 위치가 초기 위치보다 큰경우
                if ((perDX >= 0.0f && x <= defPos.x) || (perDX < 0.0f && x >= defPos.x)) {
                    //이동량이 +
                    endX = true;    //X 방향 이동 종료
                }
                if ((perDY >= 0.0f && y <= defPos.y) || (perDY < 0.0f && y >= defPos.y)) {
                    endY = true;    //Y 방향 이동 종료
                }
                //블록 이동
                transform.Translate(new Vector3(-perDX, -perDY, defPos.z));
            }else{
                //정방향 이동
                //이동량이 양수고 이동 위치가 초기 위치보다 큰거나
                //이동량이 음수고 이동 위치가 초기 + 이동거리 보다 작은 경우
                if ((perDX >= 0.0f && x >= defPos.x + moveX) || (perDX < 0.0f && x <= defPos.x + moveX)){
                    endX = true;    //X 방향 이동 종료
                }
                if ((perDY >= 0.0f && y >= defPos.y + moveY) || (perDY < 0.0f && y <= defPos.y + moveY)){
                    endY = true;    //Y 방향 이동 종료
                }
                //블록 이동
                Vector3 v = new Vector3(perDX, perDY, defPos.z);
                transform.Translate(v);
            }

            if (endX && endY){
                //이동 종료
                if (isReverse){
                    //위치가 어긋나는것을 방지하기 위해 정면 방향이동으로 돌아가기 전에 초기 위치로 돌림
                    transform.position = defPos;
                }
                isReverse = !isReverse; //값을 반전 시킴
                isCanMove = false;      //이동 가능 값을 false
                if (isMoveWhenOn == false){
                    //올라 탓을 때 움직이는 값이 꺼져있는 경우
                    Invoke("Move", weight);  // weight 만큼 지연 후 다시 이동
                }
            }
        }
    }

OnCollisionenter2D()

캐릭터가 블록위에 올라타면 블록의 자식으로 해서 같이 움직이게 해준다 캐릭터가 블록위에서 벗어나면 풀어준다. OnCollisionEnter와 Exit를 이용해서 구현한다.

private void OnCollisionEnter2D(Collision2D collision)  {
    if (collision.gameObject.tag == "Player") {
        //접촉한것이 플레이어라면 이동 블록의 자식으로 만들기
        collision.transform.SetParent(transform);
        if (isMoveWhenOn) {
            //올라탔을 때 움직이는 경우면 
            isCanMove = true;   //이동하게 만들기
        }
    }
}
//접촉 종료
private void OnCollisionExit2D(Collision2D collision) {
    if (collision.gameObject.tag == "Player") {
        //접촉한것이 플레이어라면 이동 블록의 자식에서 제외시킴
        collision.transform.SetParent(null);
    }
}

블록에 스크립트를 어태치합니다

블록을 프리팹으로 만들고 프리팹을 끌어 씬뷰에 하나더 배치합니다. 스크립트의 변수 설정이 둘다 비슷한데 하나는 IsMoveWhenOn이 체크되어 있어 게임 실행후는 멈춰있지만 올라타면 움직이고 내리면 멈춥니다.

MoveX는 자동으로 움직일 거리입니다.

Times는 자동으로 움직일 편도 시간입니다. 3이면 3초동안 진행합니다.

 

MovingBlock.cs
0.00MB

+ Recent posts