//------------------------------------------------------------------------- // 3. UPDATE LOOP //------------------------------------------------------------------------- function update(dt) { updatePlayer(dt) updateBullets(dt) updateMonsters(dt) updateVehicles(dt) checkTreasure() checkPickups() checkLiquids() // updateDoors(dt) checkDoors() // ! Vielleicht eigene update Funktion für Musik schreiben // theme.level1.play() } function updatePlayer(dt) { updateEntity(player, dt) } function updateVehicles(dt) { var n, max for (n = 0, max = vehicles.length; n < max; n++) updateVehicle(vehicles[n], dt) } function updateVehicle(vehicle, dt) { updateEntity(vehicle, dt) if ( overlap(player.x, player.y, TILE, TILE, vehicle.x, vehicle.y, TILE, TILE) ) { if (player.dy > 0 && vehicle.y - player.y > TILE / 2) // ! Wie mache ich hier den collision check? Achtung, die height und width des Vehicles ist immer noch 16x16 console.log('log collision vehicle!') } } function updateMonsters(dt) { var n, max for (n = 0, max = monsters.length; n < max; n++) updateMonster(monsters[n], dt) } function updateMonster(monster, dt) { // monster.slimeMonster && console.log('log monster ', monster) if (!monster.dead) { updateEntity(monster, dt) // ! TILE ist immer nur eine feste Zahl "16" if ( overlap(player.x, player.y, TILE, TILE, monster.x, monster.y, TILE, TILE) ) { // ! Erklärung wie das hier funktioniert und evtl. eine allgemeine Funktion daraus machen, die prüft, ob etwas Vertikal kollidiert. if (player.dy > 0 && monster.y - player.y > TILE / 2) killMonster(monster) else if (player.vul) { reduceHitpoints(player, 1) } } } } function shoot(player) { //globalObject.ammo > 0 ? sfx.shoot.play() : sfx.click.play() if (player.shooting) return player.shooting = true const bulletX = player.x const bulletY = player.y const direction = player.flipped const weaponType = player?.currentWeapon || 'simpleGun' if (globalObject.ammo > 0) { sfx.shoot.play() globalObject.ammo-- bullets.push({ bullet: true, width: 4, height: 4, flipped: player.flipped, originX: bulletX, originY: bulletY, x: bulletX, y: bulletY + player.height / 2, directionLeft: direction, ammoType: weaponType, damage: 1, }) } else { sfx.click.play() } setTimeout(() => { player.shooting = false }, 200) } function updateBullets(dt) { var n, max for (n = 0, max = bullets.length; n < max; n++) updateBullet(bullets[n], dt) } function updateBullet(bullet, dt) { if (!!bullet) { if (bullet.directionLeft) { bullet.x = bullet.x - ammoType.velocity } else { bullet.x = bullet.x + ammoType.velocity } var n, max, monster, thisBullet for (n = 0, max = monsters.length; n < max; n++) { monster = monsters[n] thisBullet = bullet if (!monster.dead) { if ( overlap( thisBullet.x, thisBullet.y, ammoType.width, ammoType.height, monster.x, monster.y, TILE, TILE ) ) reduceHitpoints(monster, bullet.damage), sfx.explode.play(), destroyBullet(bullet) } } if ( (!bullet.directionLeft && bullet.x > bullet.originX + ammoType.distance) || (bullet.directionLeft && bullet.x < bullet.originX - ammoType.distance) ) { destroyBullet(bullet) } } } function destroyBullet(bullet) { const index = bullets.indexOf(bullet) if (index > -1) { bullets.splice(index, 1) } } function checkTreasure() { var n, max, t for (n = 0, max = treasure.length; n < max; n++) { t = treasure[n] if ( !t.collected && overlap(player.x, player.y, TILE, TILE, t.x, t.y, TILE, TILE) ) collectTreasure(t) } } function checkPickups() { var n, max, p for (n = 0, max = pickups.length; n < max; n++) { p = pickups[n] if ( !p.collected && overlap(player.x, player.y, TILE, TILE, p.x, p.y, TILE, TILE) ) collectPickup(p) } } function collectPickup(p) { // console.log('log pickup ', p) if (p.extralife) { addExtraLife(p) } if (p.ammo) { addAmmo(p) } if (p.health) { addHitPoints(p) } } function addExtraLife(p) { globalObject.lifes++ p.collected = true sfx.smb_powerup.play() } function addHitPoints(p) { if (globalObject.hitpoints < globalObject.maxHitpoints) { globalObject.hitpoints++ p.collected = true sfx.stomp.play() } } function addAmmo(p) { if (globalObject.ammo < globalObject.maxAmmo) { globalObject.ammo++ p.collected = true sfx.kick.play() } } // * Check if Player is Swimming or Diving function checkLiquids() { var n, max, l for (n = 0, max = liquids.length; n < max; n++) { l = liquids[n] if (overlap(player.x, player.y, TILE, TILE, l.x, l.y, l.width, l.height)) { !player.swimming && sfx.splash.play() player.dy = player.dy / 1.15 if (!player.swimming) player.jumping = false player.swimming = true } else { player.swimming = false } if ( overlap( player.x, player.y - player.height, TILE, TILE, l.x, l.y, l.width, l.height ) ) { player.diving = true reduceOxygen(4) } else { player.diving = false replenishOxygen(16) } } } // * Reduce & Replenish Oxygen Functions function reduceOxygen(rate) { if (player.diving && globalObject.oxygen >= 0) { globalObject.oxygen -= rate / 100 } else if (player.vul) { reduceHitpoints(player, 1, 2000) } } function replenishOxygen(rate) { if (globalObject.oxygen <= globalObject.maxOxygen) { globalObject.oxygen += rate / 100 } } function checkDoors() { // ! Hier habe ich rudimentär einen Levelwechsel eingebaut. // ! Was noch fehlt ist, dass ein globales Player-Objekt beibehalten wird. var n, max, t for (n = 0, max = doors.length; n < max; n++) { t = doors[n] if ( overlap( player.x, player.y, TILE * 2, TILE * 2, t.x, t.y, TILE * 2, TILE * 2 ) ) player.interact && useDoor(t) } } function useDoor(t) { let leadsTo switch (t.leadsTo) { case 'level1': leadsTo = levelObject.level1 break case 'level2': leadsTo = levelObject.level2 break case 'level3': leadsTo = levelObject.level3 break } sfx.openDoor.play() levelTransition(leadsTo) } function levelTransition(level) { setTimeout(() => { _initLevel(level) }, 800) } function killMonster(monster) { globalObject.killed++ monster.dead = true sfx.killMonster.play() } // * Take Damage Function function reduceHitpoints(entity, damage, timeout) { const milliceconds = timeout || 1500 if ( entity.player ? globalObject.hitpoints > 1 : entity.currentHitpoints > 1 ) { entity.player ? (globalObject.hitpoints -= damage) : (entity.currentHitpoints -= damage) entity.vul = false entity.hurt = true sfx.takeDamage.play() setTimeout(() => { entity.vul = true entity.hurt = false }, milliceconds) } else killEntity(entity) } function killEntity(entity) { // console.log('killEntity: ', entity) if (entity.player === true) { killPlayer(entity) } if (entity.monster === true) { killMonster(entity) } } function killPlayer(player) { sfx.die.play() player.x = player.start.x player.y = player.start.y player.dx = player.dy = 0 globalObject.hitpoints = player.maxHitpoints globalObject.oxygen = globalObject.maxOxygen globalObject.lifes-- // console.log('log globalObject: ', globalObject.lifes) } function collectTreasure(t) { globalObject.collected++ t.collected = true sfx.pickup.play() } function updateEntity(entity, dt) { var wasleft = entity.dx < 0, wasright = entity.dx > 0, falling = entity.falling, swimming = entity.swimming || false, friction = entity.friction * (falling && !swimming ? 0.5 : swimming ? 0.1 : 1), impulse = entity.impulse, swimImpulse = entity.impulse / 3, accel = entity.accel * (falling && !swimming ? 0.5 : swimming ? 0.1 : 1), gravity = swimming ? METER * 8 : METER * GRAVITY entity.ddx = 0 entity.ddy = gravity // ! Hier wir gravity angewandt // * Hier wird die Entity bewegt. if (entity.left) (entity.ddx = entity.ddx - accel), (entity.flipped = true) else if (wasleft) entity.ddx = entity.ddx + friction if (entity.right) (entity.ddx = entity.ddx + accel), (entity.flipped = false) else if (wasright) entity.ddx = entity.ddx - friction if (entity.jump) { if (!entity.jumping && !falling && !swimming) { jump(entity) } else if (!entity.jumping && swimming) { swim(entity) } } function jump(entity) { sfx.jump.play() entity.ddy = entity.ddy - impulse // an instant big force impulse entity.jumping = true } function swim(entity) { sfx.swim.play() entity.ddy = entity.down ? entity.ddy + swimImpulse : entity.up ? entity.ddy - swimImpulse * 2 : entity.ddy - swimImpulse entity.jumping = true setTimeout(() => { entity.jumping = false }, 400) } // ! "dt" ist hier identisch mit "step", was in der index.js in die update() gegeben wird. Konstant bei ca. 0.01666 //console.log('log entity.x + dt * entity.dx: ', player.x + dt * player.dx) entity.x = entity.x + dt * entity.dx entity.y = entity.y + dt * entity.dy entity.dx = bound(entity.dx + dt * entity.ddx, -entity.maxdx, entity.maxdx) entity.dy = bound(entity.dy + dt * entity.ddy, -entity.maxdy, entity.maxdy) if ((wasleft && entity.dx > 0) || (wasright && entity.dx < 0)) { entity.dx = 0 // clamp at zero to prevent friction from making us jiggle side to side } var tx = p2t(entity.x), ty = p2t(entity.y), nx = entity.x % TILE, ny = entity.y % TILE, cell = tcell(tx, ty, mapWidth), //! Prüft ob eine Cell oben oder links angrenzt cellright = tcell(tx + 1, ty, mapWidth), celldown = tcell(tx, ty + 1, mapWidth), celldiag = tcell(tx + 1, ty + 1, mapWidth) // ! logischerweise muss das prüfen, ob eine Cell unten rechts angrenzt // ? Ist das hier der Collision Check? // entity.player && console.log('log cell ', cell) // entity.player && console.log('log cellright ', cellright) entity.player && console.log('log ny ', ny) // entity.player && console.log('log celldiag ', celldiag) // ! Die Collision prüft einfach nur, ob an den Player eine Cell angrenzt (!0) oder nicht (0). if (entity.dy > 0) { if ((celldown && !cell) || (celldiag && !cellright && nx)) { entity.y = t2p(ty) entity.dy = 0 entity.falling = false entity.jumping = false ny = 0 } } else if (entity.dy < 0) { if ((cell && !celldown) || (cellright && !celldiag && nx)) { entity.y = t2p(ty + 1) entity.dy = 0 cell = celldown cellright = celldiag ny = 0 } } if (entity.dx > 0) { if ((cellright && !cell) || (celldiag && !celldown && ny)) { entity.x = t2p(tx) entity.dx = 0 } } else if (entity.dx < 0) { if ((cell && !cellright) || (celldown && !celldiag && ny)) { entity.x = t2p(tx + 1) entity.dx = 0 } } if (entity.monster || entity.slimeMonster) { if (entity.left && (cell || !celldown)) { entity.left = false entity.right = true } else if (entity.right && (cellright || !celldiag)) { entity.right = false entity.left = true } } entity.falling = !(celldown || (nx && celldiag)) }