Charger des images
load.js
const PNG = [
"apple",
"pineapple",
"watermelon",
"grape",
"bean",
]
Charger deux effets sonores
load.js
const MP3 = [
"get",
"met",
"wooosh",
"off",
"hit",
]
Créer deux nouveaux composants
component.js
function item(type, p) {
const param = {
offset: vec2(0, -20),
...p
}
return {
type: type,
id: "item",
collectItem() {
if (this.is("respawn")) this.hideObject()
else destroy(this)
splashFX(this.pos, { offset: param.offset })
play("get")
}
}
}
function inventory(p) {
const param = {
giveKey: "space",
numbers: false,
payDistance: 200,
itemSize: 40,
speakHeight: 60,
speakPadding: 4,
stackMargin: 20,
margin: 10,
updateDelay: 0.2,
displayDelay: 4,
textSize: 40,
textOffset: vec2(10, 34),
deleteOnRespawn: false,
...p
}
return {
currentCondition: null,
currentInventory: [],
inventoryVisible: false,
inventorySavedTime: 0,
speakBox: null,
id: "inventory",
add() {
this.onCollide("item", (c) => this.collectItem(c))
this.onCollide("condition", (c) => (this.currentCondition = c))
onKeyPress(param.giveKey, () => this.payCondition())
},
update() {
if (!this.speakBox) this.inventorySetup()
if (
this.currentCondition != null &&
this.pos.dist(this.currentCondition.pos) < param.payDistance
)
this.showInventory()
else if (this.inventoryVisible && time() - this.inventorySavedTime > param.displayDelay)
this.showInventory(false)
},
resetInventory() {
if (param.deleteOnRespawn) {
for (const e of this.currentInventory) e.count = 0
}
this.updateInventoryDisplay()
this.showInventory(true)
},
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.beenHidden) {
c.collectItem()
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(e.type)
e.icons.push(obj)
}
}
}
}
if (!b) {
if (param.numbers) {
const obj = this.initInventoryIcon(c.type)
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.type)
this.currentInventory.push({ type: c.type, count: 1, icons: [obj] })
}
}
this.updateInventoryDisplay()
this.showInventory()
}
},
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.type))
}
this.updateInventoryDisplay()
},
initInventoryIcon(type) {
return this.speakBox.add([
sprite(type, { 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
}
}
init = true
},
}
}
Déclarer des symboles
levelConf.js
const LEVEL_CONFIG = {
// paramètres du niveau
tileWidth: 64,
tileHeight: 64,
backgroundColor: "afe1ff",
gravity: 3200,
tiles: {
// listes des objets à placer dans les niveaux
"q": () => [ // pastèque
sprite("watermelon"),
item("watermelon"),
area(),
anchor("bot"),
offscreen({ hide: true }),
],
"p": () => [ // pomme
sprite("apple"),
item("apple"),
area(),
anchor("bot"),
offscreen({ hide: true }),
],
"r": () => [ // raisins
sprite("grape"),
item("grape"),
area(),
anchor("bot"),
offscreen({ hide: true }),
],
"n": () => [ // ananas
sprite("pineapple"),
item("pineapple"),
area(),
anchor("bot"),
offscreen({ hide: true }),
],
"#": () => [ // player
sprite("bean"),
platformerController(),
alive(),
opacity(),
scale(),
health(1, 4),
area(),
anchor("bot"),
body(),
respawn(),
falling(),
coloring(),
animator(),
],
"=": () => [ // block
sprite("grass"),
area(),
body({ isStatic: true }),
anchor("bot"),
offscreen({ hide: true }),
],
},
}
Modifier un symbole
levelConf.js
levelConf
"#": () => [ // player
inventory(),
sprite("bean"),
platformerController(),
alive(),
opacity(),
scale(),
health(1, 4),
area(),
anchor("bot"),
body(),
respawn(),
falling(),
coloring(),
animator(),
],
Placer les objets
level.js
const LEVELS = [
// liste des niveaux du jeu
{
map: `
p p
===
= q
r r ===
===
n
===
#
======
`,
},
];
inventory
levelConf.js
tiles :
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),
}),