Hello all,
I'm trying to design a boss fight for the end of my Mario game, and I'm finding a considerable mental block when it comes to the actual logic.
I have a Boss class, which is just the Player class copied in full, that draws just fine onto the canvas
class Boss{
constructor() {
this.speed = 10 //for testing
this.position = {
x: 300,
y: 500
}
this.velocity = {
x:0,
y:0
}
this.scale = 0.3
this.width = 398 * this.scale
this.height = 353 * this.scale
this.image = createImage(spriteMarioStandRight)
this.frames = 0
this.sprites = {
stand: {
right: createImage(spriteMarioStandRight),
left: createImage(spriteMarioStandLeft),
//cropWidth: 398,
//width: 398 * this.scale
fireFlower: {
right: createImage(spriteFireFlowerStandRight),
left: createImage(spriteFireFlowerStandLeft)
}
},
run: {
right: createImage(spriteMarioRunRight),
left: createImage(spriteMarioRunLeft),
//cropWidth: 398,
//width: 398 * this.scale,
fireFlower: {
right: createImage(spriteFireFlowerRunRight),
left: createImage(spriteFireFlowerRunLeft)
}
},
jump: {
right: createImage(spriteMarioJumpRight),
left: createImage(spriteMarioJumpLeft),
//cropWidth: 398,
//width: 398 * this.scale
fireFlower: {
right: createImage(spriteFireFlowerJumpRight),
left: createImage(spriteFireFlowerJumpLeft)
}
}
}
this.currentSprite = this.sprites.stand.left
this.currentCropWidth = 398
//this.powerups = {fireFlower: false, policies: false, tech: false, people: false}
this.invincible = false
this.opacity = 1
this.health = 10000
//this.attack = "jump"
//this.attackMap = ["jump", "lunge", "techAttack", "policyAttack", "peopleAttack", "none"]
}
draw() {
c.save()
c.globalAlpha = this.opacity
c.fillStyle = 'rgba(255,0,0, .2)'
c.fillRect(this.position.x, this.position.y, this.width, this.height)
c.drawImage(
this.currentSprite,
this.currentCropWidth * this.frames,
0,
this.currentCropWidth,
353,
this.position.x,
this.position.y,
this.width,
this.height
)
c.restore()
}
update() {
this.frames++
const {currentSprite, sprites} = this
if (this.frames > 58 && ((currentSprite === sprites.stand.right) || (currentSprite === sprites.stand.left) || (currentSprite === sprites.stand.fireFlower.left) || (currentSprite === sprites.stand.fireFlower.right))){
this.frames = 0
}
else if (this.frames > 28 && ((currentSprite === sprites.run.right) || (currentSprite === sprites.run.left) || (currentSprite === sprites.run.fireFlower.left) || (currentSprite === sprites.run.fireFlower.right))){
this.frames = 0
}
else if (currentSprite === sprites.jump.right || currentSprite === sprites.jump.left || currentSprite === sprites.jump.fireFlower.right || currentSprite === sprites.jump.fireFlower.left){
this.frames = 0
}
this.draw()
this.position.y += this.velocity.y
this.position.x += this.velocity.x
if ((this.position.y + this.height + this.velocity.y) <= canvas.height){
this.velocity.y += gravity
//console.log(this.position.y)
}
if (this.invincible) {
if (this.opacity === 1) {
this.opacity = 0
}
else{
this.opacity = 1
}
} else this.opacity = 1
}
}I instantiate the boss object same as the player:
let boss = new Boss()Then I follow the same rules as the flagpole for confirming the object exists:
if(boss) {
boss.update()
boss.velocity.x = 0 }At the end of the level, I want to have the player character fight a boss with 5 unique mechanics, and it's here that I'm stuck logic wise. Here are the 5 mechanics I have in mind:
Technology based attack: boss throws 1s and 0s shaped objects at the player, player has a specific power up to defend from this
Policy based attack: boss charges the player quickly on the ground, player has to jump on top of the boss.
People based attack: boss is cloned multiple times, new boss objects created above the player, player has to dodge and shoot the boss objects falling towards them
Jumping attack: boss simply jumps towards the player in random fashion
None: boss taunts the player in the logs
I was thinking of using an attack map similar to the platformsMap array functionality from the videos so I can easily change up the order if the game gets stale. I don't have working code but here's what I had thought up for this:
while boss.health != 0 {
if(player.health == 0) {
loseCondition()
}
else {
action = bossAttackMap[getRandomInteger(0, bossAttackMap.length-1)]//getRandomInteger is a function I made to return a random result from two integers
switch (action) {
case "jump":{
boss.velocity.y -= 10
boss.position.x = getRandomInteger(boss.position.x, lastPlatform.width)
break
}
case "technologyAttack" :{
flood = getRandomInteger(25, 75)
while (flood >= 0){
goombas.push(new Goomba{//goomba constructor})
flood -= 1
}
//goombas just push themselves offscreen and roll over into garbage collection
break
}
case "policyAttack":{
boss.speed = getRandomInteger(10,30)
boss.velocity.x += boss.speed
boss.position.x += boss.velocity.x
//simulated charging
break
}
case "peopleAttack" :{
let bosses = []
flood = getRandomInteger(10, 30)
while (flood >= 0){
bosses.push(new Boss())
clone = bosses[bosses.length-1]
clone.position.y = getRandomInteger(lastPlatform.height, canvas.height)
clone.position.x = getRandomInteger(lastPlatform.position.x, lastPlatform.width)
flood -= 1
}
//boss clones fall towards the ground and roll over into garbage collection
}
case "none" :{
let taunts = ["pre canned taunt 1", "pre canned taunt 2",..."pre canned taunt n"]
let randomTaunt = getRandomInteger(0, taunts.length - 1)
console.log(taunts[randomTaunt])
}
}
}
}The first problem I ran into was having this code execute rapidly. I'd like there to be delays so my jump attack doesn't just yeet the boss right off the screen, but I can't seem to get the timeout functionality to work like this, and I'm all out of ideas.
Any help is appreciated, thanks in advance!
Want to participate?
Create a free Chris Courses account to begin