아케이드 티딩 가이드 목록으로
🚀 직접 따라해보기

통 피하기 (Barrel Dodger)

💡 참고: 이 가이드는 메이크코드 아케이드 튜토리얼 Happy Flower를 바탕으로 제작되었습니다.

🎯 학습 목표:

  • 타일맵(Tilemap)을 사용하여 게임의 바닥과 벽을 디자인합니다.
  • 가속도(ay, Gravity)를 적용하여 점프와 착지 물리 효과를 만듭니다.
  • 상태 확인(Is Hitting Tile)을 통해 이중 점프를 방지하는 논리를 배웁니다.
  • 타일 위치(Tile Location)를 기준으로 적(장애물)을 생성하고 배치합니다.
1

맵과 바닥 만들기

캐릭터가 밟고 서 있을 바닥을 만들어 봅시다.

  1. ||scene:장면||에서 ||scene:타일맵 설정|| 블록을 가져옵니다.
  2. 타일맵 편집기를 열고 10x8 크기로 설정한 뒤, 바닥 타일을 그리고 벽(Wall)을 칠해줍니다.
💡 벽 그리기: 빨간색 벽 툴을 선택하여 바닥 타일 위에 칠해야 캐릭터가 통과하지 않고 그 위에 설 수 있습니다.
Draw Tilemap
// @highlight
namespace myTiles {
    //% blockIdentity=images._tile
    export const tile0 = img`
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
    `
}
// @highlight
tiles.setTilemap(tiles.createTilemap(
    hex`0a0008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000303030303030303030303030303030303030303`,
    img`
        . . . . . . . . . .
        . . . . . . . . . .
        . . . . . . . . . .
        . . . . . . . . . .
        . . . . . . . . . .
        . . . . . . . . . .
        2 2 2 2 2 2 2 2 2 2
        2 2 2 2 2 2 2 2 2 2
    `,
    [myTiles.tile0,sprites.builtin.brick,sprites.builtin.oceanDepths0,sprites.builtin.oceanDepths3],
    TileScale.Sixteen
))
2

영웅 등장 (중력 적용)

주인공을 만들고, 공중에 뜨지 않도록 중력을 적용합니다.


||variables(sprites):[mySprite]를 스프라이트 설정|| 블록으로 캐릭터를 생성합니다.

||scene:[mySprite]를 타일맵 ... 위에 놓기|| 블록으로 1열 5행즈음에 배치합니다.

► 좌우로만 움직이도록 ||controller:[mySprite]를 버튼으로 이동 (vx: 100, vy: 0)||으로 설정합니다. (vy를 0으로 하면 위아래 키로 움직이지 않습니다.)

중력: ||sprites:[mySprite] 가속도 설정 (ax, ay)|| 블록에서 ay(아래쪽 가속도)500으로 설정하여 바닥으로 떨어지게 합니다.

namespace myTiles {
    //% blockIdentity=images._tile
    export const tile0 = img`
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
    `
}
// @highlight
tiles.setTilemap(tiles.createTilemap(
    hex`0a0008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000303030303030303030303030303030303030303`,
    img`
        . . . . . . . . . .
        . . . . . . . . . .
        . . . . . . . . . .
        . . . . . . . . . .
        . . . . . . . . . .
        . . . . . . . . . .
        2 2 2 2 2 2 2 2 2 2
        2 2 2 2 2 2 2 2 2 2
    `,
    [myTiles.tile0,sprites.builtin.brick,sprites.builtin.oceanDepths0,sprites.builtin.oceanDepths3],
    TileScale.Sixteen
))
// @highlight
let mySprite = sprites.create(img`
    . . . . . . 5 . 5 . . . . . . .
    . . . . . f 5 5 5 f f . . . . .
    . . . . f 1 5 2 5 1 6 f . . . .
    . . . f 1 6 6 6 6 6 1 6 f . . .
    . . . f 6 6 f f f f 6 1 f . . .
    . . . f 6 f f d d f f 6 f . . .
    . . f 6 f d f d d f d f 6 f . .
    . . f 6 f d 3 d d 3 d f 6 f . .
    . . f 6 6 f d d d d f 6 6 f . .
    . f 6 6 f 3 f f f f 3 f 6 6 f .
    . . f f d 3 5 3 3 5 3 d f f . .
    . . f d d f 3 5 5 3 f d d f . .
    . . . f f 3 3 3 3 3 3 f f . . .
    . . . f 3 3 5 3 3 5 3 3 f . . .
    . . . f f f f f f f f f f . . .
    . . . . . f f . . f f . . . . .
`, SpriteKind.Player)
// @highlight
tiles.placeOnTile(mySprite, tiles.getTileLocation(1, 5))
// @highlight
controller.moveSprite(mySprite, 100, 0)
// @highlight
mySprite.ay = 500
3

점프하기 (조건문)

바닥에 있을 때만 점프할 수 있도록 만들어 봅시다.


||controller:[A] 버튼을 [누를 때]|| 블록을 가져옵니다.

||logic:만약(if) [참] 이면|| 블록을 넣고, 조건에 ||scene:[mySprite]가 [아래쪽(bottom)] 벽에 닿았는가?||를 넣습니다.

► 바닥에 닿아있다면, ||sprites:[mySprite] 속도 설정 vy||-200으로 설정하여 위로 솟구치게 합니다.

controller.A.onEvent(ControllerButtonEvent.Pressed, function () {
    // @highlight
    let mySprite: Sprite = null
    if (mySprite.isHittingTile(CollisionDirection.Bottom)) {
        // @highlight
        mySprite.vy = -200
    }
})
4

굴러오는 통 (장애물)

오른쪽에서 통이 굴러오도록 만들어 봅시다.


||game:게임 업데이트시 [2000] ms 마다|| 블록을 추가합니다.

||sprites:[projectile]을 발사체로...|| 블록을 사용하여 통을 만듭니다. 속도 vx-100 ~ -80 사이의 랜덤값으로 설정하세요.

위치 잡기: ||scene:[projectile]을 타일맵 [col 9, row 5] 위에 놓기|| 블록을 사용하여 통이 바닥 바로 위에서 시작하도록 합니다.

game.onUpdateInterval(2000, function () {
    let projectile = sprites.createProjectileFromSide(img`
        . e e e e e e .
        e e e e e e e e
        1 1 1 1 1 1 1 1
        e e e e e e e e
        e e e e e e e e
        1 1 1 1 1 1 1 1
        e e e e e e e e
        . e e e e e e .
    `, randint(-100, -80), 0)
    // @highlight
    tiles.placeOnTile(projectile, tiles.getTileLocation(9, 5))
    // @highlight
    info.changeScoreBy(1)
})
5

충돌 시 게임 오버

통에 부딪히면 게임이 끝나야 합니다.


||sprites:스프라이트||에서 ||sprites:... [sprite]가 ... [otherSprite]와 닿았을 때|| 블록을 가져옵니다.

► 종류를 PlayerProjectile로 설정합니다.

► 닿으면 ||game:게임 종료 <패배>|| 블록을 실행합니다.

sprites.onOverlap(SpriteKind.Player, SpriteKind.Projectile, function (sprite, otherSprite) {
    // @highlight
    game.gameOver(false)
})
🎉

완성!

축하합니다! 통 피하기 게임을 완성했습니다.

타이밍에 맞춰 점프하며 얼마나 오래 버틸 수 있는지 시험해 보세요!

아래는 완성된 전체 블록 코드입니다.

Final Game
namespace myTiles {
    //% blockIdentity=images._tile
    export const tile0 = img`
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
    `
}
controller.A.onEvent(ControllerButtonEvent.Pressed, function () {
    if (mySprite.isHittingTile(CollisionDirection.Bottom)) {
        mySprite.vy = -200
    }
})
sprites.onOverlap(SpriteKind.Player, SpriteKind.Projectile, function (sprite, otherSprite) {
    game.gameOver(false)
})
game.onUpdateInterval(2000, function () {
    let projectile = sprites.createProjectileFromSide(img`
        . e e e e e e .
        e e e e e e e e
        1 1 1 1 1 1 1 1
        e e e e e e e e
        e e e e e e e e
        1 1 1 1 1 1 1 1
        e e e e e e e e
        . e e e e e e .
    `, randint(-100, -80), 0)
    tiles.placeOnTile(projectile, tiles.getTileLocation(9, 5))
    info.changeScoreBy(1)
})
namespace myTiles {
    //% blockIdentity=images._tile
    export const tile0 = img`
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
        . . . . . . . . . . . . . . . .
    `
}
// @highlight
tiles.setTilemap(tiles.createTilemap(
    hex`0a0008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000303030303030303030303030303030303030303`,
    img`
        . . . . . . . . . .
        . . . . . . . . . .
        . . . . . . . . . .
        . . . . . . . . . .
        . . . . . . . . . .
        . . . . . . . . . .
        2 2 2 2 2 2 2 2 2 2
        2 2 2 2 2 2 2 2 2 2
    `,
    [myTiles.tile0,sprites.builtin.brick,sprites.builtin.oceanDepths0,sprites.builtin.oceanDepths3],
    TileScale.Sixteen
))
let mySprite = sprites.create(img`
    . . . . . . 5 . 5 . . . . . . .
    . . . . . f 5 5 5 f f . . . . .
    . . . . f 1 5 2 5 1 6 f . . . .
    . . . f 1 6 6 6 6 6 1 6 f . . .
    . . . f 6 6 f f f f 6 1 f . . .
    . . . f 6 f f d d f f 6 f . . .
    . . f 6 f d f d d f d f 6 f . .
    . . f 6 f d 3 d d 3 d f 6 f . .
    . . f 6 6 f d d d d f 6 6 f . .
    . f 6 6 f 3 f f f f 3 f 6 6 f .
    . . f f d 3 5 3 3 5 3 d f f . .
    . . f d d f 3 5 5 3 f d d f . .
    . . . f f 3 3 3 3 3 3 f f . . .
    . . . f 3 3 5 3 3 5 3 3 f . . .
    . . . f f f f f f f f f f . . .
    . . . . . f f . . f f . . . . .
`, SpriteKind.Player)
tiles.placeOnTile(mySprite, tiles.getTileLocation(1, 5))
controller.moveSprite(mySprite, 100, 0)
mySprite.ay = 500