diff --git a/Games/2D_Fighting_game/README.md b/Games/2D_Fighting_game/README.md new file mode 100644 index 0000000000..199987a266 --- /dev/null +++ b/Games/2D_Fighting_game/README.md @@ -0,0 +1 @@ +# 2D Fighting Game diff --git a/Games/2D_Fighting_game/img/background.png b/Games/2D_Fighting_game/img/background.png new file mode 100644 index 0000000000..0fa288b90f Binary files /dev/null and b/Games/2D_Fighting_game/img/background.png differ diff --git a/Games/2D_Fighting_game/img/kenji/Attack1.png b/Games/2D_Fighting_game/img/kenji/Attack1.png new file mode 100644 index 0000000000..2d97fce405 Binary files /dev/null and b/Games/2D_Fighting_game/img/kenji/Attack1.png differ diff --git a/Games/2D_Fighting_game/img/kenji/Attack2.png b/Games/2D_Fighting_game/img/kenji/Attack2.png new file mode 100644 index 0000000000..b55303f7c7 Binary files /dev/null and b/Games/2D_Fighting_game/img/kenji/Attack2.png differ diff --git a/Games/2D_Fighting_game/img/kenji/Death.png b/Games/2D_Fighting_game/img/kenji/Death.png new file mode 100644 index 0000000000..0989c43330 Binary files /dev/null and b/Games/2D_Fighting_game/img/kenji/Death.png differ diff --git a/Games/2D_Fighting_game/img/kenji/Fall.png b/Games/2D_Fighting_game/img/kenji/Fall.png new file mode 100644 index 0000000000..22df71276b Binary files /dev/null and b/Games/2D_Fighting_game/img/kenji/Fall.png differ diff --git a/Games/2D_Fighting_game/img/kenji/Idle.png b/Games/2D_Fighting_game/img/kenji/Idle.png new file mode 100644 index 0000000000..7f877d7095 Binary files /dev/null and b/Games/2D_Fighting_game/img/kenji/Idle.png differ diff --git a/Games/2D_Fighting_game/img/kenji/Jump.png b/Games/2D_Fighting_game/img/kenji/Jump.png new file mode 100644 index 0000000000..01a6688fca Binary files /dev/null and b/Games/2D_Fighting_game/img/kenji/Jump.png differ diff --git a/Games/2D_Fighting_game/img/kenji/Run.png b/Games/2D_Fighting_game/img/kenji/Run.png new file mode 100644 index 0000000000..7e36b37275 Binary files /dev/null and b/Games/2D_Fighting_game/img/kenji/Run.png differ diff --git a/Games/2D_Fighting_game/img/kenji/Take hit.png b/Games/2D_Fighting_game/img/kenji/Take hit.png new file mode 100644 index 0000000000..48df0fbd43 Binary files /dev/null and b/Games/2D_Fighting_game/img/kenji/Take hit.png differ diff --git a/Games/2D_Fighting_game/img/samuraiMack/Attack1.png b/Games/2D_Fighting_game/img/samuraiMack/Attack1.png new file mode 100644 index 0000000000..92500f60ab Binary files /dev/null and b/Games/2D_Fighting_game/img/samuraiMack/Attack1.png differ diff --git a/Games/2D_Fighting_game/img/samuraiMack/Attack2.png b/Games/2D_Fighting_game/img/samuraiMack/Attack2.png new file mode 100644 index 0000000000..3e484d87dd Binary files /dev/null and b/Games/2D_Fighting_game/img/samuraiMack/Attack2.png differ diff --git a/Games/2D_Fighting_game/img/samuraiMack/Death.png b/Games/2D_Fighting_game/img/samuraiMack/Death.png new file mode 100644 index 0000000000..4754bd0cff Binary files /dev/null and b/Games/2D_Fighting_game/img/samuraiMack/Death.png differ diff --git a/Games/2D_Fighting_game/img/samuraiMack/Fall.png b/Games/2D_Fighting_game/img/samuraiMack/Fall.png new file mode 100644 index 0000000000..b9b4c29c53 Binary files /dev/null and b/Games/2D_Fighting_game/img/samuraiMack/Fall.png differ diff --git a/Games/2D_Fighting_game/img/samuraiMack/Idle.png b/Games/2D_Fighting_game/img/samuraiMack/Idle.png new file mode 100644 index 0000000000..bf9ca2ff09 Binary files /dev/null and b/Games/2D_Fighting_game/img/samuraiMack/Idle.png differ diff --git a/Games/2D_Fighting_game/img/samuraiMack/Jump.png b/Games/2D_Fighting_game/img/samuraiMack/Jump.png new file mode 100644 index 0000000000..c08a30b273 Binary files /dev/null and b/Games/2D_Fighting_game/img/samuraiMack/Jump.png differ diff --git a/Games/2D_Fighting_game/img/samuraiMack/Run.png b/Games/2D_Fighting_game/img/samuraiMack/Run.png new file mode 100644 index 0000000000..519ce09d1f Binary files /dev/null and b/Games/2D_Fighting_game/img/samuraiMack/Run.png differ diff --git a/Games/2D_Fighting_game/img/samuraiMack/Take Hit - white silhouette.png b/Games/2D_Fighting_game/img/samuraiMack/Take Hit - white silhouette.png new file mode 100644 index 0000000000..1f286d5a2a Binary files /dev/null and b/Games/2D_Fighting_game/img/samuraiMack/Take Hit - white silhouette.png differ diff --git a/Games/2D_Fighting_game/img/samuraiMack/Take Hit.png b/Games/2D_Fighting_game/img/samuraiMack/Take Hit.png new file mode 100644 index 0000000000..bda48d9770 Binary files /dev/null and b/Games/2D_Fighting_game/img/samuraiMack/Take Hit.png differ diff --git a/Games/2D_Fighting_game/img/shop.png b/Games/2D_Fighting_game/img/shop.png new file mode 100644 index 0000000000..d5ffabc4a2 Binary files /dev/null and b/Games/2D_Fighting_game/img/shop.png differ diff --git a/Games/2D_Fighting_game/index.html b/Games/2D_Fighting_game/index.html new file mode 100644 index 0000000000..846ae69034 --- /dev/null +++ b/Games/2D_Fighting_game/index.html @@ -0,0 +1,124 @@ + + + + + + + + +
+ +
+ +
+
+
+
+ + +
+ 10 +
+ +
+
+
+
+
+
+
+ Tie +
+ +
+ + + + + + diff --git a/Games/2D_Fighting_game/index.js b/Games/2D_Fighting_game/index.js new file mode 100644 index 0000000000..1fdc1033d2 --- /dev/null +++ b/Games/2D_Fighting_game/index.js @@ -0,0 +1,332 @@ +const canvas = document.querySelector('canvas') +const c = canvas.getContext('2d') + +canvas.width = 1024 +canvas.height = 576 + +c.fillRect(0, 0, canvas.width, canvas.height) + +const gravity = 0.7 + +const background = new Sprite({ + position: { + x: 0, + y: 0 + }, + imageSrc: './img/background.png' +}) + +const shop = new Sprite({ + position: { + x: 600, + y: 128 + }, + imageSrc: './img/shop.png', + scale: 2.75, + framesMax: 6 +}) + +const player = new Fighter({ + position: { + x: 0, + y: 0 + }, + velocity: { + x: 0, + y: 0 + }, + offset: { + x: 0, + y: 0 + }, + imageSrc: './img/samuraiMack/Idle.png', + framesMax: 8, + scale: 2.5, + offset: { + x: 215, + y: 157 + }, + sprites: { + idle: { + imageSrc: './img/samuraiMack/Idle.png', + framesMax: 8 + }, + run: { + imageSrc: './img/samuraiMack/Run.png', + framesMax: 8 + }, + jump: { + imageSrc: './img/samuraiMack/Jump.png', + framesMax: 2 + }, + fall: { + imageSrc: './img/samuraiMack/Fall.png', + framesMax: 2 + }, + attack1: { + imageSrc: './img/samuraiMack/Attack1.png', + framesMax: 6 + }, + takeHit: { + imageSrc: './img/samuraiMack/Take Hit - white silhouette.png', + framesMax: 4 + }, + death: { + imageSrc: './img/samuraiMack/Death.png', + framesMax: 6 + } + }, + attackBox: { + offset: { + x: 100, + y: 50 + }, + width: 160, + height: 50 + } +}) + +const enemy = new Fighter({ + position: { + x: 400, + y: 100 + }, + velocity: { + x: 0, + y: 0 + }, + color: 'blue', + offset: { + x: -50, + y: 0 + }, + imageSrc: './img/kenji/Idle.png', + framesMax: 4, + scale: 2.5, + offset: { + x: 215, + y: 167 + }, + sprites: { + idle: { + imageSrc: './img/kenji/Idle.png', + framesMax: 4 + }, + run: { + imageSrc: './img/kenji/Run.png', + framesMax: 8 + }, + jump: { + imageSrc: './img/kenji/Jump.png', + framesMax: 2 + }, + fall: { + imageSrc: './img/kenji/Fall.png', + framesMax: 2 + }, + attack1: { + imageSrc: './img/kenji/Attack1.png', + framesMax: 4 + }, + takeHit: { + imageSrc: './img/kenji/Take hit.png', + framesMax: 3 + }, + death: { + imageSrc: './img/kenji/Death.png', + framesMax: 7 + } + }, + attackBox: { + offset: { + x: -170, + y: 50 + }, + width: 170, + height: 50 + } +}) + +console.log(player) + +const keys = { + a: { + pressed: false + }, + d: { + pressed: false + }, + ArrowRight: { + pressed: false + }, + ArrowLeft: { + pressed: false + } +} + +decreaseTimer() + +function animate() { + window.requestAnimationFrame(animate) + c.fillStyle = 'black' + c.fillRect(0, 0, canvas.width, canvas.height) + background.update() + shop.update() + c.fillStyle = 'rgba(255, 255, 255, 0.15)' + c.fillRect(0, 0, canvas.width, canvas.height) + player.update() + enemy.update() + + player.velocity.x = 0 + enemy.velocity.x = 0 + + // player movement + + if (keys.a.pressed && player.lastKey === 'a') { + player.velocity.x = -5 + player.switchSprite('run') + } else if (keys.d.pressed && player.lastKey === 'd') { + player.velocity.x = 5 + player.switchSprite('run') + } else { + player.switchSprite('idle') + } + + // jumping + if (player.velocity.y < 0) { + player.switchSprite('jump') + } else if (player.velocity.y > 0) { + player.switchSprite('fall') + } + + // Enemy movement + if (keys.ArrowLeft.pressed && enemy.lastKey === 'ArrowLeft') { + enemy.velocity.x = -5 + enemy.switchSprite('run') + } else if (keys.ArrowRight.pressed && enemy.lastKey === 'ArrowRight') { + enemy.velocity.x = 5 + enemy.switchSprite('run') + } else { + enemy.switchSprite('idle') + } + + // jumping + if (enemy.velocity.y < 0) { + enemy.switchSprite('jump') + } else if (enemy.velocity.y > 0) { + enemy.switchSprite('fall') + } + + // detect for collision & enemy gets hit + if ( + rectangularCollision({ + rectangle1: player, + rectangle2: enemy + }) && + player.isAttacking && + player.framesCurrent === 4 + ) { + enemy.takeHit() + player.isAttacking = false + + gsap.to('#enemyHealth', { + width: enemy.health + '%' + }) + } + + // if player misses + if (player.isAttacking && player.framesCurrent === 4) { + player.isAttacking = false + } + + // this is where our player gets hit + if ( + rectangularCollision({ + rectangle1: enemy, + rectangle2: player + }) && + enemy.isAttacking && + enemy.framesCurrent === 2 + ) { + player.takeHit() + enemy.isAttacking = false + + gsap.to('#playerHealth', { + width: player.health + '%' + }) + } + + // if player misses + if (enemy.isAttacking && enemy.framesCurrent === 2) { + enemy.isAttacking = false + } + + // end game based on health + if (enemy.health <= 0 || player.health <= 0) { + determineWinner({ player, enemy, timerId }) + } +} + +animate() + +window.addEventListener('keydown', (event) => { + if (!player.dead) { + switch (event.key) { + case 'd': + keys.d.pressed = true + player.lastKey = 'd' + break + case 'a': + keys.a.pressed = true + player.lastKey = 'a' + break + case 'w': + player.velocity.y = -20 + break + case ' ': + player.attack() + break + } + } + + if (!enemy.dead) { + switch (event.key) { + case 'ArrowRight': + keys.ArrowRight.pressed = true + enemy.lastKey = 'ArrowRight' + break + case 'ArrowLeft': + keys.ArrowLeft.pressed = true + enemy.lastKey = 'ArrowLeft' + break + case 'ArrowUp': + enemy.velocity.y = -20 + break + case 'ArrowDown': + enemy.attack() + + break + } + } +}) + +window.addEventListener('keyup', (event) => { + switch (event.key) { + case 'd': + keys.d.pressed = false + break + case 'a': + keys.a.pressed = false + break + } + + // enemy keys + switch (event.key) { + case 'ArrowRight': + keys.ArrowRight.pressed = false + break + case 'ArrowLeft': + keys.ArrowLeft.pressed = false + break + } +}) diff --git a/Games/2D_Fighting_game/js/classes.js b/Games/2D_Fighting_game/js/classes.js new file mode 100644 index 0000000000..679412b6a7 --- /dev/null +++ b/Games/2D_Fighting_game/js/classes.js @@ -0,0 +1,218 @@ +class Sprite { + constructor({ + position, + imageSrc, + scale = 1, + framesMax = 1, + offset = { x: 0, y: 0 } + }) { + this.position = position + this.width = 50 + this.height = 150 + this.image = new Image() + this.image.src = imageSrc + this.scale = scale + this.framesMax = framesMax + this.framesCurrent = 0 + this.framesElapsed = 0 + this.framesHold = 5 + this.offset = offset + } + + draw() { + c.drawImage( + this.image, + this.framesCurrent * (this.image.width / this.framesMax), + 0, + this.image.width / this.framesMax, + this.image.height, + this.position.x - this.offset.x, + this.position.y - this.offset.y, + (this.image.width / this.framesMax) * this.scale, + this.image.height * this.scale + ) + } + + animateFrames() { + this.framesElapsed++ + + if (this.framesElapsed % this.framesHold === 0) { + if (this.framesCurrent < this.framesMax - 1) { + this.framesCurrent++ + } else { + this.framesCurrent = 0 + } + } + } + + update() { + this.draw() + this.animateFrames() + } +} + +class Fighter extends Sprite { + constructor({ + position, + velocity, + color = 'red', + imageSrc, + scale = 1, + framesMax = 1, + offset = { x: 0, y: 0 }, + sprites, + attackBox = { offset: {}, width: undefined, height: undefined } + }) { + super({ + position, + imageSrc, + scale, + framesMax, + offset + }) + + this.velocity = velocity + this.width = 50 + this.height = 150 + this.lastKey + this.attackBox = { + position: { + x: this.position.x, + y: this.position.y + }, + offset: attackBox.offset, + width: attackBox.width, + height: attackBox.height + } + this.color = color + this.isAttacking + this.health = 100 + this.framesCurrent = 0 + this.framesElapsed = 0 + this.framesHold = 5 + this.sprites = sprites + this.dead = false + + for (const sprite in this.sprites) { + sprites[sprite].image = new Image() + sprites[sprite].image.src = sprites[sprite].imageSrc + } + } + + update() { + this.draw() + if (!this.dead) this.animateFrames() + + // attack boxes + this.attackBox.position.x = this.position.x + this.attackBox.offset.x + this.attackBox.position.y = this.position.y + this.attackBox.offset.y + + // draw the attack box + // c.fillRect( + // this.attackBox.position.x, + // this.attackBox.position.y, + // this.attackBox.width, + // this.attackBox.height + // ) + + this.position.x += this.velocity.x + this.position.y += this.velocity.y + + // gravity function + if (this.position.y + this.height + this.velocity.y >= canvas.height - 96) { + this.velocity.y = 0 + this.position.y = 330 + } else this.velocity.y += gravity + } + + attack() { + this.switchSprite('attack1') + this.isAttacking = true + } + + takeHit() { + this.health -= 20 + + if (this.health <= 0) { + this.switchSprite('death') + } else this.switchSprite('takeHit') + } + + switchSprite(sprite) { + if (this.image === this.sprites.death.image) { + if (this.framesCurrent === this.sprites.death.framesMax - 1) + this.dead = true + return + } + + // overriding all other animations with the attack animation + if ( + this.image === this.sprites.attack1.image && + this.framesCurrent < this.sprites.attack1.framesMax - 1 + ) + return + + // override when fighter gets hit + if ( + this.image === this.sprites.takeHit.image && + this.framesCurrent < this.sprites.takeHit.framesMax - 1 + ) + return + + switch (sprite) { + case 'idle': + if (this.image !== this.sprites.idle.image) { + this.image = this.sprites.idle.image + this.framesMax = this.sprites.idle.framesMax + this.framesCurrent = 0 + } + break + case 'run': + if (this.image !== this.sprites.run.image) { + this.image = this.sprites.run.image + this.framesMax = this.sprites.run.framesMax + this.framesCurrent = 0 + } + break + case 'jump': + if (this.image !== this.sprites.jump.image) { + this.image = this.sprites.jump.image + this.framesMax = this.sprites.jump.framesMax + this.framesCurrent = 0 + } + break + + case 'fall': + if (this.image !== this.sprites.fall.image) { + this.image = this.sprites.fall.image + this.framesMax = this.sprites.fall.framesMax + this.framesCurrent = 0 + } + break + + case 'attack1': + if (this.image !== this.sprites.attack1.image) { + this.image = this.sprites.attack1.image + this.framesMax = this.sprites.attack1.framesMax + this.framesCurrent = 0 + } + break + + case 'takeHit': + if (this.image !== this.sprites.takeHit.image) { + this.image = this.sprites.takeHit.image + this.framesMax = this.sprites.takeHit.framesMax + this.framesCurrent = 0 + } + break + + case 'death': + if (this.image !== this.sprites.death.image) { + this.image = this.sprites.death.image + this.framesMax = this.sprites.death.framesMax + this.framesCurrent = 0 + } + break + } + } +} diff --git a/Games/2D_Fighting_game/js/utils.js b/Games/2D_Fighting_game/js/utils.js new file mode 100644 index 0000000000..042213f831 --- /dev/null +++ b/Games/2D_Fighting_game/js/utils.js @@ -0,0 +1,37 @@ +function rectangularCollision({ rectangle1, rectangle2 }) { + return ( + rectangle1.attackBox.position.x + rectangle1.attackBox.width >= + rectangle2.position.x && + rectangle1.attackBox.position.x <= + rectangle2.position.x + rectangle2.width && + rectangle1.attackBox.position.y + rectangle1.attackBox.height >= + rectangle2.position.y && + rectangle1.attackBox.position.y <= rectangle2.position.y + rectangle2.height + ) +} + +function determineWinner({ player, enemy, timerId }) { + clearTimeout(timerId) + document.querySelector('#displayText').style.display = 'flex' + if (player.health === enemy.health) { + document.querySelector('#displayText').innerHTML = 'Tie' + } else if (player.health > enemy.health) { + document.querySelector('#displayText').innerHTML = 'Player 1 Wins' + } else if (player.health < enemy.health) { + document.querySelector('#displayText').innerHTML = 'Player 2 Wins' + } +} + +let timer = 60 +let timerId +function decreaseTimer() { + if (timer > 0) { + timerId = setTimeout(decreaseTimer, 1000) + timer-- + document.querySelector('#timer').innerHTML = timer + } + + if (timer === 0) { + determineWinner({ player, enemy, timerId }) + } +} diff --git a/README.md b/README.md index 200f2735aa..89d5e10b5a 100644 --- a/README.md +++ b/README.md @@ -1677,6 +1677,7 @@ This repository also provides one such platforms where contributers come over an |[Pokemon_Adventure_Game](https://github.com/kunjgit/GameZone/tree/main/Games/Pokemon_Adventure_Game)| |[Garden-Builder-game](https://github.com/kunjgit/GameZone/tree/main/Games/Garden-Builder-game)| +|[2D_Fighting_Game](https://github.com/kunjgit/GameZone/tree/main/Games/2D_Fighting_Game)| | [Airhockey_game](https://github.com/kunjgit/GameZone/tree/main/Games/Airhockey_game)| diff --git a/assets/images/2D_Fighting_Game.png b/assets/images/2D_Fighting_Game.png new file mode 100644 index 0000000000..ac79adf704 Binary files /dev/null and b/assets/images/2D_Fighting_Game.png differ diff --git a/assets/js/gamesData.json b/assets/js/gamesData.json index 0b394cff3a..a1ad7cafbf 100644 --- a/assets/js/gamesData.json +++ b/assets/js/gamesData.json @@ -3375,11 +3375,16 @@ "thumbnailUrl": "Brain_Game.png" }, "633":{ + "gameTitle" : "2D Fighting Game", + "gameUrl": "2D_Fighting_Game", + "thumbnailUrl": "2D_Fighting_Game.png" + }, + "634":{ "gameTitle" : "Cosmic_Blast", "gameUrl": "Cosmic_Blast", "thumbnailUrl": "Cosmic_Blast.png" }, - "634":{ + "635":{ "gameTitle" : "IKnowYou-Mind-Reading-Game", "gameUrl": "IKnowYou-Mind-Reading-Game", "thumbnailUrl": "IKnowYou-Mind-Reading-Game.png"