diff --git a/Games/Alien_Invasion/.DS_Store b/Games/Alien_Invasion/.DS_Store
new file mode 100644
index 0000000000..74e30099e6
Binary files /dev/null and b/Games/Alien_Invasion/.DS_Store differ
diff --git a/Games/Alien_Invasion/README..md b/Games/Alien_Invasion/README..md
new file mode 100644
index 0000000000..17a09c4382
--- /dev/null
+++ b/Games/Alien_Invasion/README..md
@@ -0,0 +1,20 @@
+# AttackAlienInvaders Game App
+A cool 2D alien planet exploration steampunk-themed game application with techniques of vanilla JavaScript, HTML5, CSS3 and HTML Canvas. From sprite animation to parallax backgrounds, the game App is completely built from scratch, with no frameworks or libraries, using HTML, CSS and plain vanilla JavaScript. The game contains richful premium art assets for characters, environments and props.
+
+### [Game Won Demo](https://github.com/KrystalZhang612/KrystalZhang-AttackAlienInvaders-Game-App/blob/main/testing-result-AttackAlienInvader-game-app/Won%20Game.mov): Most Wondrous! Well done explorer!
+https://user-images.githubusercontent.com/72481348/198857930-95a5c040-1d47-4ca6-b5a6-15ac05e8e520.mov
+### [Game Lost Demo](https://github.com/KrystalZhang612/KrystalZhang-AttackAlienInvaders-Game-App/blob/main/testing-result-AttackAlienInvader-game-app/Lost%20Game.mov): Blazed! Get my repair kit and try again!
+https://user-images.githubusercontent.com/72481348/198857699-86d076d4-f746-435b-89ec-333ad1ba01b8.mov
+
+# Game Premiere Storyline
+***Central Computer***:
+`These alien creatures have very similar physiology to the earth seahorses. Their bodies can easily cut through the thick atmosphere. They can move very fast.`
+***Explorer***:
+`Seahorses hives are being attacked by something. This one has been damaged. I wonder if you can hack into this creature’s central computer to control it for a while.`
+***Central Computer***:
+`It is surprisingly easy to override its circuits. Seems like these machines are not used by our technology. I’m getting a lot of new data.`
+***Central Computer***:
+`The atmosphere on this planet is thick enough to allow heavy silicon-based lifeforms to float but smoke is blocking most of the sunlight. Many creatures developed artificial lights and glowing appendages to see through the heavy clouds. The Seahorse sentinel has a basic attack that’s powerful against weak enemies, but if it absorbs energy from one of the overcharged creatures, it gets additional firepower for a short period of time and it instantly replenishes its ammo. Ammo also automatically recharges over time. It seems we just need to help it to get through these aggressive swarms in time so it can join its hive.`
+- There is a stream of data about multiple different species.
+- The alien creatures in the hood of their ecosystem have special movements, special abilities, and interact with the environments on other planets.
+
diff --git a/Games/Alien_Invasion/index.html b/Games/Alien_Invasion/index.html
new file mode 100644
index 0000000000..760bb1af1b
--- /dev/null
+++ b/Games/Alien_Invasion/index.html
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+ AttackAlienInvader Game
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Games/Alien_Invasion/script.js b/Games/Alien_Invasion/script.js
new file mode 100644
index 0000000000..5e50da0a0c
--- /dev/null
+++ b/Games/Alien_Invasion/script.js
@@ -0,0 +1,543 @@
+window.addEventListener('load', function () {
+ //canvas setup
+ const canvas = document.getElementById('canvas1');
+ const ctx = canvas.getContext('2d');
+ canvas.width = 1000;
+ canvas.height = 500;
+
+ class InputHandler {
+ constructor(game) {
+ this.game = game;
+ window.addEventListener('keydown', e => {
+ if (((e.key === 'ArrowUp') ||
+ (e.key === 'ArrowDown')
+ ) && this.game.keys.indexOf(e.key) === - 1) {
+ this.game.keys.push(e.key);
+ } else if (e.key === ' ') {
+ this.game.player.shootTop();
+ } else if (e.key === 'd') {
+ this.game.debug = !this.game.debug;
+ }
+ });
+ window.addEventListener('keyup', e => {
+ if (this.game.keys.indexOf(e.key) > -1) {
+ this.game.keys.splice(this.game.keys.indexOf(e.key), 1);
+ }
+ });
+ }
+ }
+
+ class Projectile {
+ constructor(game, x, y) {
+ this.game = game;
+ this.x = x;
+ this.y = y;
+ this.width = 10;
+ this.height = 3;
+ this.speed = 3;
+ this.markedForDeletion = false;
+ this.image = document.getElementById('projectile');
+ }
+ update() {
+ this.x += this.speed;
+ if (this.x > this.game.width * 0.8) this.markedForDeletion = true;
+ }
+ draw(context) {
+ context.drawImage(this.image, this.x, this.y);
+ }
+ }
+
+ class Particle {
+ constructor(game, x, y) {
+ this.game = game;
+ this.x = x;
+ this.y = y;
+ this.image = document.getElementById('gears');
+ this.frameX = Math.floor(Math.random() * 3);
+ this.frameY = Math.floor(Math.random() * 3);
+ this.spriteSize = 50;
+ this.sizeModifier = (Math.random() * 0.5 + 0.5).toFixed(1);
+ this.size = this.spriteSize * this.sizeModifier;
+ this.speedX = Math.random() * 6 - 3;
+ this.speedY = Math.random() * -15;
+ this.gravity = 0.5;
+ this.markedForDeletion = false;
+ this.angle = 0;
+ this.va = Math.random() * 0.2 - 0.1;
+ this.bounced = 0;
+ this.bottomBounceBoundary = Math.random() * 80 + 60;
+ }
+ update() {
+ this.angle += this.va;
+ this.speedY += this.gravity;
+ this.x -= this.speedX - this.game.speed;
+ this.y += this.speedY;
+ if (this.y > this.game.height + this.size || this.x < 0 - this.size) this.markedForDeletion = true;
+ if (this.y > this.game.height - this.bottomBounceBoundary && this.bounced < 5) {
+ this.bounced++;
+ this.speedY *= -0.7;
+ }
+ }
+ draw(context) {
+ context.save();
+ context.translate(this.x, this.y);
+ context.rotate(this.angle);
+ context.drawImage(this.image, this.frameX * this.spriteSize,
+ this.frameY * this.spriteSize, this.spriteSize, this.spriteSize, this.size * -0.5,
+ this.size * -0.5, this.size, this.size);
+ context.restore();
+ }
+ }
+
+ class Player {
+ constructor(game) {
+ this.game = game;
+ this.width = 120;
+ this.height = 190;
+ this.x = 20;
+ this.y = 100;
+ this.frameX = 0;
+ this.frameY = 0;
+ this.maxFrame = 37;
+ this.speedY = 0;
+ this.maxSpeed = 3;
+ this.projectiles = [];
+ this.image = document.getElementById('player');
+ this.powerUp = false;
+ this.powerUpTimer = 0;
+ this.powerUpLimit = 10000;
+ }
+ update(deltaTime) {
+ if (this.game.keys.includes('ArrowUp')) this.speedY = -this.maxSpeed;
+ else if (this.game.keys.includes('ArrowDown')) this.speedY = this.maxSpeed;
+ else this.speedY = 0;
+ this.y += this.speedY;
+ // vertical boundaries
+ if (this.y > this.game.height - this.height * 0.5) this.y = this.game.height - this.height * 0.5;
+ else if (this.y < -this.height * 0.5) this.y - this.height * 0.5;
+ //handle projectiles
+ this.projectiles.forEach(projectile => {
+ projectile.update();
+ });
+ this.projectiles = this.projectiles.filter(projectile => !projectile.markedForDeletion);
+ //sprite animation
+ if (this.frameX < this.maxFrame) {
+ this.frameX++;
+ } else {
+ this.frameX = 0;
+ }
+ // power up
+ if (this.powerUp) {
+ if (this.powerUpTimer > this.powerUpLimit) {
+ this.powerUpTimer = 0;
+ this.powerUp = false;
+ this.frameY = 0;
+ } else {
+ this.powerUpTimer += deltaTime;
+ this.frameY = 1;
+ this.game.ammo += 0.1;
+ }
+ }
+ }
+ draw(context) {
+ if (this.game.debug) context.strokeRect(this.x, this.y, this.width, this.height);
+ this.projectiles.forEach(projectile => {
+ projectile.draw(context);
+ });
+ context.drawImage(this.image, this.frameX * this.width, this.frameY * this.height, this.width, this.height, this.x, this.y, this.width, this.height);
+
+ }
+ shootTop() {
+ if (this.game.ammo > 0) {
+ this.projectiles.push(new Projectile(this.game, this.x + 80, this.y + 30));
+ this.game.ammo--;
+ }
+ if (this.powerUp) this.shootBottom();
+ }
+ shootBottom() {
+ if (this.game.ammo > 0) {
+ this.projectiles.push(new Projectile(this.game, this.x + 80, this.y + 175));
+ }
+ }
+
+ enterPowerUp() {
+ this.powerUpTimer = 0;
+ this.powerUp = true;
+ if (this.game.ammo < this.game.maxAmmo) this.game.ammo = this.game.maxAmmo;
+ }
+ }
+ class Enemy {
+ constructor(game) {
+ this.game = game;
+ this.x = this.game.width;
+ this.speedX = Math.random() * -1.5 - 0.5;
+ this.markedForDeletion = false;
+ this.frameX = 0;
+ this.frameY = 0;
+ this.maxFrame = 37;
+ }
+ update() {
+ this.x += this.speedX - this.game.speed;
+ if (this.x + this.width < 0) this.markedForDeletion = true;
+ // sprite animation
+ if (this.frameX < this.maxFrame) {
+ this.frameX++;
+ } else this.frameX = 0;
+ }
+ draw(context) {
+ if (this.game.debug) context.strokeRect(this.x, this.y, this.width, this.height);
+ context.drawImage(this.image, this.frameX * this.width, this.frameY * this.height, this.width, this.height, this.x, this.y, this.width, this.height);
+ if (this.game.debug) {
+ context.font = '20px Bangers';
+ context.fillText(this.lives, this.x, this.y);
+ }
+ }
+ }
+ class Angler1 extends Enemy {
+ constructor(game) {
+ super(game);
+ this.width = 228;
+ this.height = 169;
+ this.y = Math.random() * (this.game.height * 0.95 - this.height);
+ this.image = document.getElementById('angler1');
+ this.frameY = Math.floor(Math.random() * 3);
+ this.lives = 5;
+ this.score = this.lives;
+ }
+
+ }
+ class Angler2 extends Enemy {
+ constructor(game) {
+ super(game);
+ this.width = 213;
+ this.height = 165;
+ this.y = Math.random() * (this.game.height * 0.95 - this.height);
+ this.image = document.getElementById('angler2');
+ this.frameY = Math.floor(Math.random() * 2);
+ this.lives = 6;
+ this.score = this.lives;
+ }
+
+ }
+
+ class LuckyFish extends Enemy {
+ constructor(game) {
+ super(game);
+ this.width = 99;
+ this.height = 95;
+ this.y = Math.random() * (this.game.height * 0.95 - this.height);
+ this.image = document.getElementById('lucky');
+ this.frameY = Math.floor(Math.random() * 2);
+ this.lives = 5;
+ this.score = 15;
+ this.type = 'lucky'
+ }
+ }
+
+ class HiveWhale extends Enemy {
+ constructor(game) {
+ super(game);
+ this.width = 400;
+ this.height = 227;
+ this.y = Math.random() * (this.game.height * 0.95 - this.height);
+ this.image = document.getElementById('hivewhale');
+ this.frameY = 0;
+ this.lives = 20;
+ this.score = this.lives;
+ this.type = 'hive';
+ this.speedX = Math.random() * -1.2 - 0.2;
+ }
+ }
+
+ class Drone extends Enemy {
+ constructor(game, x, y) {
+ super(game);
+ this.width = 115;
+ this.height = 95;
+ this.x = x;
+ this.y = y;
+ this.image = document.getElementById('drone');
+ this.frameY = Math.floor(Math.random() * 2);
+ this.lives = 3;
+ this.score = this.lives;
+ this.type = 'drone';
+ this.speedX = Math.random() * -4.2 - 0.5;
+ }
+ }
+
+
+ class Layer {
+ constructor(game, image, speedModifier) {
+ this.game = game;
+ this.image = image;
+ this.speedModifier = speedModifier;
+ this.width = 1768;
+ this.height = 500;
+ this.x = 0;
+ this.y = 0;
+ }
+ update() {
+ if (this.x <= -this.width) this.x = 0;
+ this.x -= this.game.speed * this.speedModifier;
+ }
+ draw(context) {
+ context.drawImage(this.image, this.x, this.y);
+ context.drawImage(this.image, this.x + this.width, this.y);
+ }
+ }
+
+ class Background {
+ constructor(game) {
+ this.game = game;
+ this.image1 = document.getElementById('layer1');
+ this.image2 = document.getElementById('layer2');
+ this.image3 = document.getElementById('layer3');
+ this.image4 = document.getElementById('layer4');
+ this.layer1 = new Layer(this.game, this.image1, 0.2);
+ this.layer2 = new Layer(this.game, this.image2, 0.4);
+ this.layer3 = new Layer(this.game, this.image3, 1);
+ this.layer4 = new Layer(this.game, this.image4, 1.5);
+ this.layers = [this.layer1, this.layer2, this.layer3, this.layer4];
+ }
+ update() {
+ this.layers.forEach(layer => layer.update());
+ }
+ draw(context) {
+ this.layers.forEach(layer => layer.draw(context));
+ }
+
+ }
+
+ class Explosion {
+ constructor(game, x, y) {
+ this.game = game;
+ this.frameX = 0;
+ this.spriteWidth = 200;
+ this.spriteHeight = 200;
+ this.width = this.spriteWidth;
+ this.height = this.spriteHeight;
+ this.x = x - this.width * 0.5;
+ this.y = y - this.height * 0.5;
+ this.fps = 30;
+ this.time = 0;
+ this.interval = 1000 / this.fps;
+ this.markedForDeletion = false;
+ this.maxFrame = 8;
+ }
+ update(deltaTime) {
+ this.x -= this.game.speed;
+ if (this.timer > this.interval) {
+ this.frameX++;
+ this.timer = 0;
+ } else {
+ this.timer += deltaTime;
+ }
+ if (this.frameX > this.maxFrame) this.markedForDeletion = true;
+ }
+ draw(context) {
+ context.drawImage(this.image, this.frameX * this.spriteWidth, 0, this.spriteWidth,
+ this.spriteHeight, this.x, this.y, this.width, this.height);
+ }
+ }
+
+ class SmokeExplosion extends Explosion {
+ constructor(game, x, y) {
+ super(game, x, y);
+ this.image = document.getElementById('smokeExplosion');
+ }
+ }
+
+ class FireExplosion extends Explosion {
+ constructor(game, x, y) {
+ super(game, x, y);
+ this.image = document.getElementById('fireExplosion');
+ }
+ }
+
+
+ class UI {
+ constructor(game) {
+ this.game = game;
+ this.fontSize = 25;
+ this.fontFamily = 'Bangers';
+ this.color = 'yellow';
+ }
+ draw(context) {
+ context.save();
+ context.fillStyle = this.color;
+ context.shadowOffsetX = 2;
+ context.shadowOffsetY = 2;
+ context.shadowColor = 'black';
+ context.font = this.fontSize + 'px' + this.fontFamily;
+ //score
+ context.font = '20px Bangers';
+ context.fillText('Score: ' + this.game.score, 20, 40);
+
+ //timer
+ const formattedTime = (this.game.gameTime * 0.001).toFixed(1);
+ context.font = '20px Bangers';
+ context.fillText('Timer:' + formattedTime, 20, 100);
+
+ //game over messages
+ if (this.game.gameOver) {
+ context.textAlign = 'center';
+ let message1;
+ let message2;
+ if (this.game.score > this.game.winningScore) {
+ message1 = 'Most Wondrous!';
+ message2 = 'Well Done explorer!';
+ } else {
+ message1 = 'Blazes!';
+ message2 = 'Get my repair kit and try again!';
+ }
+ context.font = '50px Bangers';
+ context.fillText(message1, this.game.width * 0.5, this.game.height * 0.5 - 20);
+ context.font = '25px Bangers';
+ context.fillText(message2, this.game.width * 0.5, this.game.height * 0.5 + 20);
+ }
+ //ammo
+ if (this.game.player.powerUp) context.fillStyle = '#ffffbd';
+ for (let i = 0; i < this.game.ammo; i++) {
+ context.fillRect(20 + 5 * i, 50, 3, 20);
+ }
+ context.restore();
+ }
+ }
+ class Game {
+ constructor(width, height) {
+ this.width = width;
+ this.height = height;
+ this.background = new Background(this);
+ this.player = new Player(this);
+ this.input = new InputHandler(this);
+ this.ui = new UI(this);
+ this.keys = [];
+ this.enemies = [];
+ this.particles = [];
+ this.explosions = [];
+ this.enemyTimer = 0;
+ this.enemyInterval = 2000;
+ this.ammo = 20;
+ this.maxAmmo = 50;
+ this.ammoTimer = 0;
+ this.ammoInterval = 350;
+ this.gameOver = false;
+ this.score = 0;
+ this.winningScore = 80;
+ this.gameTime = 0;
+ this.timeLimit = 30000;
+ this.speed = 1;
+ this.debug = false;
+
+ }
+ update(deltaTime) {
+ if (!this.gameOver) this.gameTime += deltaTime;
+ if (this.gameTime > this.timeLimit) this.gameOver = true;
+ this.background.update();
+ this.background.layer4.update();
+ this.player.update(deltaTime);
+ if (this.ammoTimer > this.ammoInterval) {
+ if (this.ammo < this.maxAmmo) this.ammo++;
+ this.ammoTimer = 0;
+ } else {
+ this.ammoTimer += deltaTime;
+ }
+ this.particles.forEach(particle => particle.update());
+ this.particles = this.particles.filter(particle => !particle.markedForDeletion);
+ this.explosions.forEach(explosion => explosion.update(deltaTime));
+ this.explosions = this.explosions.filter(explosion => !explosion.markedForDeletion);
+ this.enemies.forEach(enemy => {
+ enemy.update();
+ if (this.checkCollision(this.player, enemy)) {
+ enemy.markedForDeletion = true;
+ this.addExplosion(enemy);
+ for (let i = 0; i < enemy.score; i++) {
+ this.particles.push(new Particle(this, enemy.x + enemy.width * 0.5, enemy.y + enemy.height * 0.5));
+ }
+ if (enemy.type === 'lucky') this.player.enterPowerUp();
+ else if (!this.gameOver) this.score--;
+ }
+ this.player.projectiles.forEach(projectile => {
+ if (this.checkCollision(projectile, enemy)) {
+ enemy.lives--;
+ projectile.markedForDeletion = true;
+ this.particles.push(new Particle(this, enemy.x + enemy.width * 0.5, enemy.y + enemy.height * 0.5));
+ if (enemy.lives <= 0) {
+ for (let i = 0; i < enemy.score; i++) {
+ this.particles.push(new Particle(this, enemy.x + enemy.width * 0.5, enemy.y + enemy.height * 0.5));
+ }
+ enemy.markedForDeletion = true;
+ this.addExplosion(enemy);
+ if (enemy.type === 'hive') {
+ for (let i = 0; i < 5; i++) {
+ this.enemies.push(new Drone(this, enemy.x + Math.random() * enemy.width,
+ enemy.y + Math.random() * enemy.height + 0.5));
+ }
+ }
+ if (!this.gameOver) this.score += enemy.score;
+ /*if (this.score > this.winningScore) this.gameOver = true;*/
+ }
+ }
+ });
+ });
+ this.enemies = this.enemies.filter(enemy => !enemy.markedForDeletion);
+ if (this.enemyTimer > this.enemyInterval && !this.gameOver) {
+ this.addEnemy();
+ this.enemyTimer = 0;
+ } else {
+ this.enemyTimer += deltaTime;
+ }
+ }
+ draw(context) {
+ this.background.draw(context);
+ this.ui.draw(context);
+ this.player.draw(context);
+ this.particles.forEach(particle => particle.draw(context));
+ this.enemies.forEach(enemy => {
+ enemy.draw(context);
+ });
+ this.explosions.forEach(explosion => {
+ explosion.draw(context);
+ });
+ this.background.layer4.draw(context);
+ }
+ addEnemy() {
+ const randomize = Math.random();
+ if (randomize < 0.3) this.enemies.push(new Angler1(this));
+ else if (randomize < 0.6) this.enemies.push(new Angler2(this));
+ else if (randomize < 0.7) this.enemies.push(new HiveWhale(this));
+ else this.enemies.push(new LuckyFish(this));
+ }
+ addExplosion(enemy) {
+ const randomize = Math.random();
+ if (randomize < 0.5) {
+ this.explosions.push(new SmokeExplosion(this, enemy.x + enemy.width * 0.5, enemy.y + enemy.height * 0.5));
+ }
+ else {
+ this.explosions.push(new FireExplosion(this, enemy.x + enemy.width * 0.5, enemy.y + enemy.height * 0.5));
+ }
+ }
+ checkCollision(rect1, rect2) {
+ return (rect1.x < rect2.x + rect2.width &&
+ rect1.x + rect1.width > rect2.x &&
+ rect1.y < rect2.y + rect2.height &&
+ rect1.height + rect1.y > rect2.y)
+ }
+
+ }
+
+ const game = new Game(canvas.width, canvas.height);
+ let lastTime = 0;
+ //animation loop
+ function animate(timeStamp) {
+ const deltaTime = timeStamp - lastTime;
+ console.log(deltaTime);
+ lastTime = timeStamp;
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ game.draw(ctx);
+ game.update(deltaTime);
+ requestAnimationFrame(animate);
+ }
+ animate(0);
+});
+
diff --git a/Games/Alien_Invasion/style.css b/Games/Alien_Invasion/style.css
new file mode 100644
index 0000000000..268a5f3b93
--- /dev/null
+++ b/Games/Alien_Invasion/style.css
@@ -0,0 +1,34 @@
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+#canvas1 {
+ border: 5px solid black;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ background: #4d79bc;
+ max-width: 100%;
+ max-height: 100%;
+ font-family: 'Bangers', cursive;
+}
+
+#layer1,
+#layer2,
+#layer3,
+#layer4,
+#player,
+#angler1,
+#angler2,
+#lucky,
+#projectile,
+#gears,
+#hivewhale,
+#drone,
+#smokeExplosion,
+#fireExplosion {
+ display: none;
+}
\ No newline at end of file
diff --git a/Games/Car_Racing_Game/README.md b/Games/Car_Racing_Game/README.md
new file mode 100644
index 0000000000..8843bf7fd4
--- /dev/null
+++ b/Games/Car_Racing_Game/README.md
@@ -0,0 +1,74 @@
+# **Car Racing Game**
+---
+
+
+
+## **Description 📃**
+
+Car Racing Game is an exhilarating 2D racing game where players control a red car and compete against a computer-controlled green car. The game features multiple levels with increasing difficulty, realistic collision detection, and smooth controls.
+
+
+## **Functionalities 🎮**
+
+- **Player and Computer Cars**: Control the red car and race against the green computer car.
+- **Levels and Progression**: Complete levels by reaching the finish line before the computer car. Each level offers more challenges and obstacles.
+- **Collision Detection**: Realistic collision detection with track borders and other cars.
+- **Speed Control**: Adjust the speed of your car using the arrow keys.
+- **Direction Control**: Rotate your car left or right to navigate through the track.
+- **Game Over and Reset**: The game ends if the player fails to beat the computer car. Reset the game to try again.
+
+
+
+## **How to Play? 🕹️**
+
+1. **Start the Game**: Launch the game to begin.
+
+### Controls:
+
+- Use the **left** and **right arrow keys** to rotate the car.
+- Use the **up arrow key** to accelerate forward.
+- Use the **down arrow key** to slow down or reverse.
+
+2. **Navigate the Track**: Avoid collisions with track borders and other cars.
+3. **Complete Levels**: Reach the finish line before the computer car to advance to the next level.
+4. **Game Over**: If the computer car reaches the finish line first, it's game over. Reset the game to try again.
+
+
+
+## **Installation and Running the Game 🚀**
+### Prerequisites
+
+- Python 3.x
+- Pygame library
+
+### Steps
+
+1. **Clone the repository**:
+ ```sh
+ git clone https://github.com/shellyverma/game.git
+ ```
+
+2. **Navigate to the game directory**:
+ ```sh
+ cd game
+ ```
+
+3. **Install the dependencies** (assuming you have Python and pip installed):
+ ```sh
+ pip install pygame
+ ```
+
+4. **Run the game**:
+ ```sh
+ python main.py
+ ```
+
+
+
+## **Screenshots 📸**
+
+
+![Game Screenshot](https://github.com/shellyverma/game/blob/ea66450ffb4afb9fb849ea685e39a131d5da8849/Screenshot%20.png?raw=true)
+
+---
+
diff --git a/Games/Car_Racing_Game/__pycache__/utils.cpython-312.pyc b/Games/Car_Racing_Game/__pycache__/utils.cpython-312.pyc
new file mode 100644
index 0000000000..c9a648cf14
Binary files /dev/null and b/Games/Car_Racing_Game/__pycache__/utils.cpython-312.pyc differ
diff --git a/Games/Car_Racing_Game/git b/Games/Car_Racing_Game/git
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/Games/Car_Racing_Game/imgs/finish.png b/Games/Car_Racing_Game/imgs/finish.png
new file mode 100644
index 0000000000..9f78c56d0c
Binary files /dev/null and b/Games/Car_Racing_Game/imgs/finish.png differ
diff --git a/Games/Car_Racing_Game/imgs/grass.png b/Games/Car_Racing_Game/imgs/grass.png
new file mode 100644
index 0000000000..dbacd680f0
Binary files /dev/null and b/Games/Car_Racing_Game/imgs/grass.png differ
diff --git a/Games/Car_Racing_Game/imgs/green-car.png b/Games/Car_Racing_Game/imgs/green-car.png
new file mode 100644
index 0000000000..053ec9949c
Binary files /dev/null and b/Games/Car_Racing_Game/imgs/green-car.png differ
diff --git a/Games/Car_Racing_Game/imgs/red-car.png b/Games/Car_Racing_Game/imgs/red-car.png
new file mode 100644
index 0000000000..49441823ca
Binary files /dev/null and b/Games/Car_Racing_Game/imgs/red-car.png differ
diff --git a/Games/Car_Racing_Game/imgs/track-border.png b/Games/Car_Racing_Game/imgs/track-border.png
new file mode 100644
index 0000000000..a5d9a46a57
Binary files /dev/null and b/Games/Car_Racing_Game/imgs/track-border.png differ
diff --git a/Games/Car_Racing_Game/imgs/track.png b/Games/Car_Racing_Game/imgs/track.png
new file mode 100644
index 0000000000..bd6954dace
Binary files /dev/null and b/Games/Car_Racing_Game/imgs/track.png differ
diff --git a/Games/Car_Racing_Game/main.py b/Games/Car_Racing_Game/main.py
new file mode 100644
index 0000000000..756c470b6b
--- /dev/null
+++ b/Games/Car_Racing_Game/main.py
@@ -0,0 +1,328 @@
+import pygame
+import time
+import math
+from utils import scale_image, blit_rotate_center, blit_text_center
+import os
+
+# Initialize Pygame font module
+pygame.font.init()
+
+# Set the base directory to the GameZone/Games/Car_Racing_Game directory
+base_dir = os.path.join(os.getcwd(), "Games", "Car_Racing_Game")
+imgs_dir = os.path.join(base_dir, "imgs")
+
+# Debug prints to ensure directories are correct
+print("Base directory:", base_dir)
+print("Images directory:", imgs_dir)
+if os.path.exists(imgs_dir):
+ print("Files in imgs directory:", os.listdir(imgs_dir))
+else:
+ print("imgs directory not found")
+
+# Attempt to load the images with error handling
+try:
+ GRASS = scale_image(pygame.image.load(os.path.join(imgs_dir, "grass.png")), 2.5)
+ print("grass.png loaded successfully")
+except FileNotFoundError as e:
+ print("Error loading grass.png:", e)
+
+try:
+ TRACK = scale_image(pygame.image.load(os.path.join(imgs_dir, "track.png")), 0.9)
+ print("track.png loaded successfully")
+except FileNotFoundError as e:
+ print("Error loading track.png:", e)
+
+try:
+ TRACK_BORDER = scale_image(pygame.image.load(os.path.join(imgs_dir, "track-border.png")), 0.9)
+ TRACK_BORDER_MASK = pygame.mask.from_surface(TRACK_BORDER)
+ print("track-border.png loaded successfully")
+except FileNotFoundError as e:
+ print("Error loading track-border.png:", e)
+
+try:
+ FINISH = pygame.image.load(os.path.join(imgs_dir, "finish.png"))
+ FINISH_MASK = pygame.mask.from_surface(FINISH)
+ FINISH_POSITION = (130, 250)
+ print("finish.png loaded successfully")
+except FileNotFoundError as e:
+ print("Error loading finish.png:", e)
+
+try:
+ RED_CAR = scale_image(pygame.image.load(os.path.join(imgs_dir, "red-car.png")), 0.55)
+ print("red-car.png loaded successfully")
+except FileNotFoundError as e:
+ print("Error loading red-car.png:", e)
+
+try:
+ GREEN_CAR = scale_image(pygame.image.load(os.path.join(imgs_dir, "green-car.png")), 0.55)
+ print("green-car.png loaded successfully")
+except FileNotFoundError as e:
+ print("Error loading green-car.png:", e)
+
+# Ensure TRACK is loaded before setting up the game window
+if 'TRACK' in locals():
+ # Set up the game window dimensions
+ WIDTH, HEIGHT = TRACK.get_width(), TRACK.get_height()
+ WIN = pygame.display.set_mode((WIDTH, HEIGHT))
+ pygame.display.set_caption("Racing Game!")
+
+ # Set up the main font for text display
+ MAIN_FONT = pygame.font.SysFont("comicsans", 44)
+
+ # Game settings
+ FPS = 60
+ PATH = [(175, 119), (110, 70), (56, 133), (70, 481), (318, 731), (404, 680), (418, 521), (507, 475), (600, 551), (613, 715), (736, 713),
+ (734, 399), (611, 357), (409, 343), (433, 257), (697, 258), (738, 123), (581, 71), (303, 78), (275, 377), (176, 388), (178, 260)]
+
+ # Class to manage game information such as levels and time
+ class GameInfo:
+ LEVELS = 10
+
+ def __init__(self, level=1):
+ self.level = level
+ self.started = False
+ self.level_start_time = 0
+
+ def next_level(self):
+ self.level += 1
+ self.started = False
+
+ def reset(self):
+ self.level = 1
+ self.started = False
+ self.level_start_time = 0
+
+ def game_finished(self):
+ return self.level > self.LEVELS
+
+ def start_level(self):
+ self.started = True
+ self.level_start_time = time.time()
+
+ def get_level_time(self):
+ if not self.started:
+ return 0
+ return round(time.time() - self.level_start_time)
+
+ # Abstract car class with common functionalities for player and computer cars
+ class AbstractCar:
+ def __init__(self, max_vel, rotation_vel):
+ self.img = self.IMG
+ self.max_vel = max_vel
+ self.vel = 0
+ self.rotation_vel = rotation_vel
+ self.angle = 0
+ self.x, self.y = self.START_POS
+ self.acceleration = 0.1
+
+ def rotate(self, left=False, right=False):
+ if left:
+ self.angle += self.rotation_vel
+ elif right:
+ self.angle -= self.rotation_vel
+
+ def draw(self, win):
+ blit_rotate_center(win, self.img, (self.x, self.y), self.angle)
+
+ def move_forward(self):
+ self.vel = min(self.vel + self.acceleration, self.max_vel)
+ self.move()
+
+ def move_backward(self):
+ self.vel = max(self.vel - self.acceleration, -self.max_vel/2)
+ self.move()
+
+ def move(self):
+ radians = math.radians(self.angle)
+ vertical = math.cos(radians) * self.vel
+ horizontal = math.sin(radians) * self.vel
+
+ self.y -= vertical
+ self.x -= horizontal
+
+ def collide(self, mask, x=0, y=0):
+ car_mask = pygame.mask.from_surface(self.img)
+ offset = (int(self.x - x), int(self.y - y))
+ poi = mask.overlap(car_mask, offset)
+ return poi
+
+ def reset(self):
+ self.x, self.y = self.START_POS
+ self.angle = 0
+ self.vel = 0
+
+ # Player car class with specific functionalities
+ class PlayerCar(AbstractCar):
+ IMG = RED_CAR
+ START_POS = (180, 200)
+
+ def reduce_speed(self):
+ self.vel = max(self.vel - self.acceleration / 2, 0)
+ self.move()
+
+ def bounce(self):
+ self.vel = -self.vel
+ self.move()
+
+ # Computer car class with AI functionalities
+ class ComputerCar(AbstractCar):
+ IMG = GREEN_CAR
+ START_POS = (150, 200)
+
+ def __init__(self, max_vel, rotation_vel, path=[]):
+ super().__init__(max_vel, rotation_vel)
+ self.path = path
+ self.current_point = 0
+ self.vel = max_vel
+
+ def draw_points(self, win):
+ for point in self.path:
+ pygame.draw.circle(win, (255, 0, 0), point, 5)
+
+ def draw(self, win):
+ super().draw(win)
+ # self.draw_points(win)
+
+ def calculate_angle(self):
+ target_x, target_y = self.path[self.current_point]
+ x_diff = target_x - self.x
+ y_diff = target_y - self.y
+
+ if y_diff == 0:
+ desired_radian_angle = math.pi / 2
+ else:
+ desired_radian_angle = math.atan(x_diff / y_diff)
+
+ if target_y > self.y:
+ desired_radian_angle += math.pi
+
+ difference_in_angle = self.angle - math.degrees(desired_radian_angle)
+ if difference_in_angle >= 180:
+ difference_in_angle -= 360
+
+ if difference_in_angle > 0:
+ self.angle -= min(self.rotation_vel, abs(difference_in_angle))
+ else:
+ self.angle += min(self.rotation_vel, abs(difference_in_angle))
+
+ def update_path_point(self):
+ target = self.path[self.current_point]
+ rect = pygame.Rect(
+ self.x, self.y, self.img.get_width(), self.img.get_height())
+ if rect.collidepoint(*target):
+ self.current_point += 1
+
+ def move(self):
+ if self.current_point >= len(self.path):
+ return
+
+ self.calculate_angle()
+ self.update_path_point()
+ super().move()
+
+ def next_level(self, level):
+ self.reset()
+ self.vel = self.max_vel + (level - 1) * 0.2
+ self.current_point = 0
+
+ # Function to draw the game elements on the screen
+ def draw(win, images, player_car, computer_car, game_info):
+ for img, pos in images:
+ win.blit(img, pos)
+
+ level_text = MAIN_FONT.render(
+ f"Level {game_info.level}", 1, (255, 255, 255))
+ win.blit(level_text, (10, HEIGHT - level_text.get_height() - 70))
+
+ time_text = MAIN_FONT.render(
+ f"Time: {game_info.get_level_time()}s", 1, (255, 255, 255))
+ win.blit(time_text, (10, HEIGHT - time_text.get_height() - 40))
+
+ vel_text = MAIN_FONT.render(
+ f"Vel: {round(player_car.vel, 1)}px/s", 1, (255, 255, 255))
+ win.blit(vel_text, (10, HEIGHT - vel_text.get_height() - 10))
+
+ player_car.draw(win)
+ computer_car.draw(win)
+ pygame.display.update()
+
+ # Function to handle player car movement
+ def move_player(player_car):
+ keys = pygame.key.get_pressed()
+ moved = False
+
+ if keys[pygame.K_LEFT]:
+ player_car.rotate(left=True)
+ if keys[pygame.K_RIGHT]:
+ player_car.rotate(right=True)
+ if keys[pygame.K_UP]:
+ moved = True
+ player_car.move_forward()
+ if keys[pygame.K_DOWN]:
+ moved = True
+ player_car.move_backward()
+
+ if not moved:
+ player_car.reduce_speed()
+
+ # Main game loop
+ run = True
+ clock = pygame.time.Clock()
+ images = [(GRASS, (0, 0)), (TRACK, (0, 0)),
+ (FINISH, FINISH_POSITION), (TRACK_BORDER, (0, 0))]
+ player_car = PlayerCar(4, 4)
+ computer_car = ComputerCar(2, 4, PATH)
+ game_info = GameInfo()
+
+ while run:
+ clock.tick(FPS)
+
+ draw(WIN, images, player_car, computer_car, game_info)
+
+ # Wait for the player to start the level
+ while not game_info.started:
+ blit_text_center(
+ WIN, MAIN_FONT, f"Press any key to start level {game_info.level}!")
+ pygame.display.update()
+ for event in pygame.event.get():
+ if event.type == pygame.QUIT:
+ run = False
+ break
+ if event.type == pygame.KEYDOWN:
+ game_info.start_level()
+
+ for event in pygame.event.get():
+ if event.type == pygame.QUIT:
+ run = False
+ break
+
+ move_player(player_car)
+ computer_car.move()
+
+ # Check for collisions with the track border
+ if player_car.collide(TRACK_BORDER_MASK) != None:
+ player_car.bounce()
+
+ # Check for collisions with the finish line
+ finish_poi_collide = player_car.collide(
+ FINISH_MASK, *FINISH_POSITION)
+ if finish_poi_collide != None:
+ if finish_poi_collide[1] == 0:
+ player_car.bounce()
+ else:
+ game_info.next_level()
+ player_car.reset()
+ computer_car.next_level(game_info.level)
+
+ # Check if the game is finished
+ if game_info.game_finished():
+ blit_text_center(WIN, MAIN_FONT, "You won the game!")
+ pygame.display.update()
+ pygame.time.wait(5000)
+ game_info.reset()
+ player_car.reset()
+ computer_car.reset()
+
+ pygame.quit()
+else:
+ print("TRACK not loaded. Exiting.")
diff --git a/Games/Car_Racing_Game/utils.py b/Games/Car_Racing_Game/utils.py
new file mode 100644
index 0000000000..e3aa50d2f2
--- /dev/null
+++ b/Games/Car_Racing_Game/utils.py
@@ -0,0 +1,50 @@
+import pygame
+
+def scale_image(img, factor):
+ """
+ Scale an image by a given factor.
+
+ Parameters:
+ img (pygame.Surface): The image to be scaled.
+ factor (float): The scaling factor.
+
+ Returns:
+ pygame.Surface: The scaled image.
+ """
+ size = round(img.get_width() * factor), round(img.get_height() * factor)
+ return pygame.transform.scale(img, size)
+
+def blit_rotate_center(win, image, top_left, angle):
+ """
+ Draw an image rotated around its center.
+
+ Parameters:
+ win (pygame.Surface): The surface to draw the image on.
+ image (pygame.Surface): The image to be rotated and drawn.
+ top_left (tuple): The top-left coordinates of the image.
+ angle (float): The angle to rotate the image.
+ """
+ # Rotate the image by the specified angle
+ rotated_image = pygame.transform.rotate(image, angle)
+ # Get the new rectangle of the rotated image, centered on the original image's center
+ new_rect = rotated_image.get_rect(center=image.get_rect(topleft=top_left).center)
+ # Draw the rotated image on the window
+ win.blit(rotated_image, new_rect.topleft)
+
+def blit_text_center(win, font, text):
+ """
+ Draw text centered on the window.
+
+ Parameters:
+ win (pygame.Surface): The surface to draw the text on.
+ font (pygame.font.Font): The font used to render the text.
+ text (str): The text to be rendered and drawn.
+ """
+ # Render the text with the specified font
+ render = font.render(text, 1, (200, 200, 200))
+ # Calculate the position to center the text on the window
+ position = (win.get_width() / 2 - render.get_width() / 2,
+ win.get_height() / 2 - render.get_height() / 2)
+ # Draw the text on the window
+ win.blit(render, position)
+
diff --git a/Games/Carrom/carrom.html b/Games/Carrom/carrom.html
index 91ee9e1e85..3b1fb382aa 100644
--- a/Games/Carrom/carrom.html
+++ b/Games/Carrom/carrom.html
@@ -14,7 +14,7 @@