Aller au contenu

Inventaire

Anton
  1. load.js
    const PNG = [
    "apple",
    "pineapple",
    "watermelon",
    "grape",
    "grass",
    ]
  2. load.js
    const MP3 = [
    "score",
    "wooosh",
    "off",
    ]
  3. component.js
    function collectible(p) {
    const param = {
    tag: "player",
    offset: vec2(0, -20),
    type: "collectible",
    goesToInventory: false,
    autoDestroy: true,
    ...p
    }
    return {
    id: "collectible",
    add() {
    this.onCollide(param.tag, (obj) => {
    if (!this.is("respawn") || !this.beenHidden) {
    this.trigger("picked")
    obj.trigger("pick", { sprite: this.sprite, type: param.type, goesToInventory: param.goesToInventory })
    if (param.autoDestroy) this.trigger("disapear")
    }
    })
    this.on("disapear", () => {
    if (this.is("respawn")) this.hideFromScene()
    else destroy(this)
    })
    },
    }
    }
    component.js
    function inventory(p) {
    const param = {
    giveKey: "space",
    payDistance: 200,
    deleteOnRespawn: false,
    numbers: false,
    itemSize: 40,
    speakHeight: 60,
    speakPadding: 4,
    stackMargin: 20,
    margin: 10,
    updateDelay: 0.2,
    displayDelay: 4,
    textSize: 40,
    textOffset: vec2(10, 34),
    ...p
    }
    return {
    currentCondition: null,
    currentInventory: [],
    inventoryVisible: false,
    inventorySavedTime: 0,
    speakBox: null,
    id: "inventory",
    add() {
    this.on("pick", (c) => this.collectItem(c))
    this.onCollide("condition", (c) => (this.currentCondition = c))
    this.on("respawn", () => {
    this.updateInventoryDisplay()
    this.trigger("show inventory")
    if (param.deleteOnRespawn) for (const e of this.currentInventory) e.count = 0
    })
    this.on("show inventory", () => {
    const h = param.speakHeight + param.speakPadding * 2
    if (!this.inventoryVisible) tween(-h, 0, param.updateDelay, (v) => (this.speakBox.pos.y = v), easings.easeInSin)
    this.inventoryVisible = true
    this.inventorySavedTime = time()
    })
    this.on("hide inventory", () => {
    const h = param.speakHeight + param.speakPadding * 2
    tween(0, -h, param.updateDelay, (v) => (this.speakBox.pos.y = v), easings.easeInSin)
    this.inventoryVisible = false
    })
    onKeyPress(param.giveKey, () => this.payCondition())
    },
    update() {
    if (!this.speakBox) this.inventorySetup()
    if (this.currentCondition != null && this.pos.dist(this.currentCondition.pos) < param.payDistance) this.trigger("show inventory")
    else if (this.inventoryVisible && time() - this.inventorySavedTime > param.displayDelay) this.trigger("hide inventory")
    },
    showInventory(b = true) {
    const h = param.speakHeight + param.speakPadding * 2
    if (!b) tween(0, -h, param.updateDelay, (v) => (this.speakBox.pos.y = v), easings.easeInSin)
    else if (!this.inventoryVisible) tween(-h, 0, param.updateDelay, (v) => (this.speakBox.pos.y = v), easings.easeInSin)
    this.inventoryVisible = b
    if (b) this.inventorySavedTime = time()
    },
    payCondition(d) {
    if (this.currentCondition != null && this.pos.dist(this.currentCondition.pos) < param.payDistance) {
    for (const e of this.currentCondition.conditions) {
    for (const el of this.currentInventory) {
    if (el.type == e.type) {
    const n = Math.min(e.count, el.count)
    el.count -= n
    e.count -= n
    this.updateInventoryDisplay()
    this.currentCondition.updateInventoryDisplay()
    }
    }
    }
    this.currentCondition.checkCondition(this.pos)
    }
    },
    collectItem(c) {
    if (c.goesToInventory) {
    let b = false
    for (const e of this.currentInventory) {
    if (e.type == c.type) {
    b = true
    e.count++
    if (!param.numbers) {
    while (e.icons.length < e.count) {
    const obj = this.initInventoryIcon(c.sprite)
    e.icons.push(obj)
    }
    }
    }
    }
    if (!b) {
    if (param.numbers) {
    const obj = this.initInventoryIcon(c.sprite)
    const textObj = this.speakBox.add([
    text("ok", { size: param.textSize }),
    pos(0, 0),
    fixed(),
    ])
    this.currentInventory.push({
    type: c.type,
    count: 1,
    icon: obj,
    textObj: textObj,
    })
    } else {
    const obj = this.initInventoryIcon(c.sprite)
    this.currentInventory.push({ type: c.type, count: 1, icons: [obj] })
    }
    }
    this.updateInventoryDisplay()
    this.trigger("show inventory")
    }
    },
    inventorySetup() {
    const h = param.speakHeight + param.speakPadding * 2
    this.speakBox = add([opacity(0.5), pos(0, -h), fixed()])
    for (const e of this.currentInventory) {
    e.icons = []
    for (let i = 0; i < e.count; i++) e.icons.push(this.initInventoryIcon(e.sprite))
    }
    this.updateInventoryDisplay()
    },
    initInventoryIcon(name) {
    return this.speakBox.add([
    sprite(name, { width: param.itemSize }),
    pos(0, param.speakHeight / 2),
    fixed(),
    scale(0),
    anchor("center"),
    { visible: false },
    ])
    },
    updateInventoryDisplay() {
    if (param.numbers) this.numbersDisplay()
    else this.iconsDisplay()
    },
    numbersDisplay() {
    let m = param.speakPadding + param.itemSize / 2
    for (const e of this.currentInventory) {
    if (e.count > 0) {
    const newPos = m
    if (!e.icon.visible) {
    e.textObj.hidden = false
    e.icon.pos.x = newPos
    e.textObj.pos.x = m + param.textOffset.x
    tween(
    0,
    1,
    param.updateDelay,
    (v) => (e.icon.scaleTo(v)),
    easings.easeInSin
    )
    }
    else {
    tween(
    e.icon.pos.x,
    newPos,
    param.updateDelay,
    (v) => {
    e.icon.pos.x = v
    e.textObj.pos.x = v + param.textOffset.y
    },
    easings.easeInSin
    )
    }
    e.icon.visible = true
    e.textObj.text = e.count
    e.textObj.pos.y = param.textOffset.y
    m += param.margin + Math.max(e.icon.width, e.icon.width / 2 + e.textObj.width + paaram.textOffset.x)
    }
    else if (e.icon.visible) {
    e.icon.visible = false
    e.textObj.hidden = true
    tween(
    1,
    0,
    param.updateDelay,
    (v) => (e.icon.scaleTo(v)),
    easings.easeInSin
    )
    }
    }
    },
    iconsDisplay() {
    let m = param.speakPadding + param.itemSize / 2
    for (const e of this.currentInventory) {
    for (let i = 0; i < e.icons.length; i++) {
    if (i < e.count) {
    const newPos = m
    if (!e.icons[i].visible) {
    e.icons[i].pos.x = newPos
    tween(0, 1, param.updateDelay, (v) => (e.icons[i].scaleTo(v)), easings.easeInSin)
    }
    else tween(e.icons[i].pos.x, newPos, param.updateDelay, (v) => (e.icons[i].pos.x = v), easings.easeInSin)
    e.icons[i].visible = true
    e.icons[i].z = m
    m += param.stackMargin
    }
    else {
    if (e.icons[i].visible) tween(1, 0, param.updateDelay, (v) => (e.icons[i].scaleTo(v)), easings.easeInSin)
    e.icons[i].visible = false
    }
    }
    if (e.count > 0) {
    m -= param.stackMargin
    m += e.icons[0].width
    m += param.margin
    }
    }
    },
    }
    }
  4. config.js
    const LEVEL_CONFIG = {
    // paramètres du niveau
    tileWidth: 64,
    tileHeight: 64,
    backgroundColor: "afe1ff",
    gravity: 3200,
    tiles: {
    "q": () => [ // pastèque
    sprite("watermelon"),
    collectible({
    goesToInventory: true,
    type: "watermelon"
    }),
    area(),
    anchor("bot"),
    offscreen({ hide: true }),
    ],
    "p": () => [ // pomme
    sprite("apple"),
    collectible({
    goesToInventory: true,
    type: "apple"
    }),
    area(),
    anchor("bot"),
    offscreen({ hide: true }),
    ],
    "r": () => [ // raisins
    sprite("grape"),
    collectible({
    goesToInventory: true,
    type: "grape"
    }),
    area(),
    anchor("bot"),
    offscreen({ hide: true }),
    ],
    "n": () => [ // ananas
    sprite("pineapple"),
    collectible({
    goesToInventory: true,
    type: "pineapple"
    }),
    area(),
    anchor("bot"),
    offscreen({ hide: true }),
    ],
    "#": () => [ // 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. config.js
    "#": () => [ // player 1
    inventory(),
    sprite("bean"),
    platformerController(),
    alive(),
    opacity(),
    scale(),
    health(1, 4),
    area(),
    anchor("bot"),
    body(),
    respawn(),
    falling(),
    ],
  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('disapear', 'collectible', (obj) => splashFX(obj.pos, { offset: vec2(0, -20) }))
    on('disapear', 'collectible', () => play('score'))
    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'))
    }
  7. level.js
    const LEVELS = [
    {
    map: `
    p p
    ===
    = q
    r r ===
    ===
    n
    ===
    #
    ======
    `,
    },
    ]
example
config.js
collectible({
tag: "player",
offset: vec2(0, -20),
type: "collectible",
goesToInventory: false,
autoDestroy: true
}),
example
config.js
inventory({
giveKey: "space",
payDistance: 200,
deleteOnRespawn: false,
numbers: false,
itemSize: 40,
speakHeight: 60,
speakPadding: 4,
stackMargin: 20,
margin: 10,
updateDelay: 0.2,
displayDelay: 4,
textSize: 40,
textOffset: vec2(10, 34)
}),