Aller au contenu

Personnage qui suit le joueur

  1. load.js
    const PNG = [
    "kat",
    "grass",
    ]
  2. load.js
    const MP3 = [
    "hit",
    "wooosh",
    "off",
    ]
  3. component.js
    function followTarget(p) {
    const param = {
    speed: 280,
    stopDistance: 0,
    retreat: false,
    tag: "player",
    uTurnDelay: 0.2,
    sight: 200,
    loosingSight: 400,
    jumpForce: 800,
    jumping: true,
    ...p
    }
    return {
    direction: vec2(0, 0),
    facing: 1,
    target: null,
    retreatPos: null,
    id: "follow",
    add() {
    requestAnimationFrame(() => this.retreatPos = vec2(this.pos))
    this.on("respawn", () => this.target = null)
    },
    update() {
    const isOnSight = this.target != null && this.target.pos.dist(this.pos) < param.loosingSight
    const gravity = this.gravityScale != 0
    let t
    if (!isOnSight) this.target = this.getClosestTarget()
    if (this.target) {
    const d = this.pos.dist(this.target.pos)
    if (d > param.stopDistance) t = this.target.pos.sub(this.pos)
    else t = vec2(0, 0)
    if (gravity && param.jumping && t.y < -1 && this.isGrounded())
    this.jump(param.jumpForce)
    } else if (param.retreat) {
    const d = this.pos.dist(this.retreatPos)
    if (d > param.stopDistance) t = this.retreatPos.sub(this.pos)
    else t = vec2(0, 0)
    } else t = vec2(0, 0)
    if (gravity) t.y = 0
    tween(this.direction, t.unit(), param.uTurnDelay, (v) => (this.direction = v), easings.easeOutSin)
    this.move(this.direction.scale(param.speed))
    if (this.direction.len() > 0.1) this.facing = this.direction.unit().x
    },
    getClosestTarget() {
    const targets = get(param.tag, { recursive: true })
    let closestTarget, lastDistance
    for (const e of targets) {
    const d = this.pos.dist(e.pos)
    if ((lastDistance == null || lastDistance > d) && d < param.sight) {
    lastDistance = d
    closestTarget = e
    this.trigger("spotted")
    }
    }
    return closestTarget
    },
    }
    }
    component.js
    function danger(p) {
    const param = {
    damage: 1,
    collisions: ["top", "left", "bot", "right"],
    ongoing: false,
    tag: "alive",
    ...p
    }
    return {
    add() {
    const c = param.ongoing ? "collideUpdate" : "collide"
    this.on(c, (obj, col) => this.checkDangerColission(obj, col))
    },
    checkDangerColission(obj, col) {
    if (obj.is(param.tag) && !this.hidden) {
    for (const c of param.collisions) {
    if (c == "top" && col.isTop()) obj.trigger("hit", param.damage)
    else if (c == "left" && col.isLeft()) obj.trigger("hit", param.damage)
    else if (c == "bot" && col.isBottom()) obj.trigger("hit", param.damage)
    else if (c == "right" && col.isRight()) obj.trigger("hit", param.damage)
    }
    }
    },
    }
    }
  4. config.js
    const LEVEL_CONFIG = {
    // paramètres du niveau
    tileWidth: 64,
    tileHeight: 64,
    backgroundColor: "afe1ff",
    gravity: 3200,
    tiles: {
    "K": () => [ // chat hostile
    sprite("kat"),
    area(),
    anchor("bot"),
    body(),
    followTarget({ jumping: false }),
    color("ff9696"),
    danger({ tag: "player" }),
    scale(),
    falling(),
    respawn({ onDeath: true }),
    opacity(),
    alive(),
    health(1),
    ],
    "k": () => [ // chat passif
    sprite("kat"),
    area(),
    anchor("bot"),
    body(),
    followTarget({ stopDistance: 120 }),
    falling(),
    scale(),
    respawn({ onDeath: true }),
    opacity(),
    alive(),
    health(1),
    ],
    "#": () => [ // player 1
    sprite("bean"),
    platformerController(),
    alive(),
    opacity(),
    scale(),
    health(1, 4),
    area(),
    anchor("bot"),
    body(),
    respawn(),
    falling(),
    ],
    "=": () => [ // block
    sprite("grass"),
    area(),
    body({ isStatic: true }),
    anchor("bot"),
    offscreen({ hide: true }),
    ],
    },
    }
  5. level.js
    const LEVELS = [
    {
    map: `
    ===
    # K k
    ===========
    `,
    },
    ]
  6. game.js
    scene("game", () => {
    const config = { ...LEVEL_CONFIG, ...LEVELS[CURRENT_LEVEL].config }
    const map = LEVELS[CURRENT_LEVEL].map.split("\n")
    const level = addLevel(map, config)
    add([
    multiplayerCamera(),
    ])
    setGravity(config.gravity)
    setBackground(config.backgroundColor)
    on('hurt', 'alive', (obj) => colorShiftFx(obj, { color: 'ff9b9b' }))
    on('hurt', 'alive', () => play('hit'))
    on('hurt', 'player', (obj) => obj.play('worry', { speed: 2, onEnd: () => obj.play('idle') }))
    on('jump', 'player', () => play('wooosh'))
    on('drop', 'player', () => play('off'))
    on('respawn', 'player', (obj) => obj.play('idle'))
    on('sleep', 'player', (obj) => obj.play('sleep'))
    on('awake', 'player', (obj) => obj.play('idle'))
    on('jump', 'player', (obj) => obj.play('jump', { speed: 4, onEnd: () => obj.play('idle') }))
    on('drop', 'player', (obj) => obj.play('worry'))
    }
example
config.js
body( { mass : 2 } ),
example
config.js
followTarget({
speed: 280,
stopDistance: 0,
retreat: false,
tag: "player",
uTurnDelay: 0.2,
sight: 200,
loosingSight: 400,
jumpForce: 800,
jumping: true
}),
example
config.js
danger({
damage: 1,
collisions: ["top", "left", "bot", "right"],
ongoing: false,
tag: "alive"
}),