Implementing a simple Christmas game with JavaScript

Implementing a simple Christmas game with JavaScript

Preface

Christmas is coming soon, and the hot lists are occupied by a bunch of Christmas trees. How could I miss such a traffic password? Everyone is posting Christmas trees, so I won’t post one. I will just share a Christmas game with everyone to play. The code is too long, so please like and collect it first.

Achieve results

The production process of a simple 2D web game has its own rules. Each part of it has a certain routine. We should

Summarize the regular parts together to form a template. Once the corresponding template is written, it can be used when a certain object is to be produced.

The template, as well as each function of the entire game process, and each js file have clear division of labor; we need to summarize them before writing,

Don't write whatever comes to mind. Although the result is the same, the code may not be very readable and maintainable, and the idea is not very

Clear.

Code

There is not much to say about the code. I will just paste the code for you. It is simple and direct. As long as it can be run and played, you can share it with your friends or play with it yourself, just for fun. I have packed the files, please send them to me if you need them.

CSS Code

body { background:rgb(8,8,58);
  margin:0;
}

#wrapper {
  width:500px;
  margin-left:auto;
  margin-right:auto;
  margin-top:20px;
}

JS code

​var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    elfImage = document.getElementById("elf");
greenGiftImage = document.getElementById("green_gift");
redGiftImage = document.getElementById("red_gift");
blueGiftImage = document.getElementById("blue_gift");
bombImage = document.getElementById("bomb");
bangImage = document.getElementById("bang");

var x = canvas.width/2;
var y = canvas.height-30;
var dx = 2;
var dy = -2;
const elfHeight = 70;
const elfWidth = 55;
var elfX = (canvas.width-elfWidth)/2;
const elfSpeed ​​= 10;
var rightPressed = false;
var leftPressed = false;
var spacePressed = false;
var spawnInterval;
var spawnTimer = 50;
var gifts = [];
var maxGift = 0;
const giftWidth = 40;
const giftHeight = 40;
var timer = 0;
var giftRotation = 0;
const TO_RADIANS = Math.PI/180; 
var score = 0;
var health = 3;
const bombChance = 5;
var elfRotation = 0;
var bangX;
var bangTime;
var snowHeight = 6;
var spawnTimeChangeInterval = 3000;
var titleColours = [];

// snowflake stuff
var snowflakes = [];
const maxSnowflakes = 80;
const snowflakeSize = 3;
const snowflakeMinSpeed ​​= 1;
const snowflakeMaxSpeed ​​= 4;
const snowflakeColours = ["rgba(255,255,255,0.95)", "rgba(255,255,255,0.65)","rgba(255,255,255,0.4)"];

const gameModes = {
  TITLE: 'title',
  PLAYING: 'playing',
  GAMEOVER: 'gameover'
};

var gameMode = gameModes.TITLE;

document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);

function keyDownHandler(e) {
  if(e.key == "Right" || e.key == "ArrowRight") {
    rightPressed = true;
  }
  else if(e.key == "Left" || e.key == "ArrowLeft") {
    leftPressed = true;
  } else if(e.code == "Space") {
    spacePressed = true;
  }
}

function keyUpHandler(e) {
  if(e.key == "Right" || e.key == "ArrowRight") {
    rightPressed = false;
  }
  else if(e.key == "Left" || e.key == "ArrowLeft") {
    leftPressed = false;
  } else if(e.code == "Space") {
    spacePressed = false;
  }
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawSnow();

  timer++;

  switch (gameMode) {
    case gameModes.TITLE:
      titleScreen(); 
      break;
    case gameModes.GAMEOVER:
      gameOver();
      break;
    case gameModes.PLAYING:
      gameLoop();
      break;
  }
}

function titleScreen() {
  if (timer > titleColours.length) timer=0;

  ctx.font = "50px Arial";
  ctx.fillStyle = titleColours[timer]; 
  ctx.fillText(`Christmas Grab Gifts!`, 0, 50);
  ctx.fillStyle = "yellow"; 

  ctx.font = "30px Arial";
  ctx.fillText(`Press the spacebar to start!`, 65, 140);

  var highScore = getHighScore();
  if (highScore != -1) ctx.fillText(`High Score: ${highScore}`, 90, 220);

  drawRotatedImage(elfImage, canvas.width/2 - elfWidth/2, 330, elfRotation, 200);
  elfRotation+=2;
  if (elfRotation > 359) elfRotation = 0;

  if (spacePressed && timer > 5) {
    setGameMode(gameModes.PLAYING);
  }
}

function gameLoop() {
  drawSnowPerson();
  spawnGifts();
  processGifts();
  drawFloor();
  drawHUD();
  drawElf();
  drawBang();

  if(rightPressed) {
    elfX += elfSpeed;
    if (elfX + elfWidth > canvas.width){
      elfX = canvas.width - (elfWidth + 5);
    }
  }
  else if(leftPressed) {
    elfX -= elfSpeed;
    if (elfX < -15){
      elfX = -15;
    }
  }
}

function gameOver() {
  ctx.font = "50px Arial";
  ctx.fillStyle = "yellow";
  ctx.fillText(`GAME OVER!`, 80, 200);
  ctx.font = "30px Arial";
  ctx.fillText(`Final score: ${score}`,130, 240);
  ctx.fillText('Press space to continue',80, 280);

  if (spacePressed && timer > 5) {
    initialiseGame();
    setGameMode(gameModes.TITLE);
  }
}

function processGifts() {
  gifts.forEach((g) => {
    if (g && g.alive) { 
      // draw gift
      drawGift(g);
      if (gy > canvas.height) {
        g.alive = false;
        if (!g.bomb) score--;
      }

      //move gift
      g.y+=g.speed;

      // rotate gift
      g.rotation+=5;
      if ( g.rotation > 359 ) g.rotation = 0 ;

      // check for collision
      if ((gy + (giftHeight/2)) >= ((canvas.height - elfHeight - snowHeight) + 20)
          && (gy<canvas.height-snowHeight+20)) {
        if ((elfX + 25) <= (gx + (giftWidth/2)) && ((elfX+20) + (elfWidth)) >= gx )
        {
          g.alive = false;
          if (!g.bomb) { 
            score+=5;
          } else {
            doBombCollision();
          }
        }
      }
    }
  });
}

function drawGift(g) {
  switch (g.colour) {
    case 1:
      drawColouredGift(greenGiftImage, g);
      break;
    case 2:
      drawColouredGift(redGiftImage, g);
      break;
    case 3:
      drawColouredGift(blueGiftImage, g);
      break;
    case 4:
      drawRotatedImage(bombImage, gx, gy, 180, 45);
      break;
  }
}

function drawColouredGift(colourImage, g) {
  drawRotatedImage(colourImage, gx, gy, g.rotation, 35);
}

function doBombCollision() {
  health--;
  bangX=elfX;
  bangTime = 5;
  if (health == 0) {
    setHighScore();
    setGameMode(gameModes.GAMEOVER);
  }
}

function drawBang() {
  if (bangTime > 0) {
    bangTime--;
    ctx.drawImage(bangImage, bangX, (canvas.height-75)-snowHeight, 75,75);
  }
}


function drawElf() {
  ctx.drawImage(elfImage, elfX,(canvas.height - elfHeight) - (snowHeight - 2),80,80);
}

function spawn() {
  var newX = 5 + (Math.random() * (canvas.width - 5));

  var colour;
  var bomb = false;

  if (randomNumber(1,bombChance) == bombChance) {
    colour = 4;
    bomb = true;
  } else {
    colour = randomNumber(1,3);
  }

  var newGift = {
    x: newX,
    y: 0,
    speed: randomNumber(2,6),
    alive: true,
    rotation: 0,
    colour: colour,
    bomb: bomb,
  };

  gifts[maxGift] = newGift;
  maxGift++;
  if (maxGift > 75) {
    maxGift = 0;
  }
}

function spawnGifts() {
  if (timer > spawnTimer) {
    spawn();
    timer = 0;
  }
}

function drawRotatedImage(image, x, y, angle, scale)
{ 
  ctx.save(); 
  ctx.translate(x, y);
  ctx.rotate(angle * TO_RADIANS);
  ctx.drawImage(image, -(image.width/2), -(image.height/2), scale, scale);
  ctx.restore(); 
}

function drawHUD() {
  ctx.font = "20px Arial";
  ctx.fillStyle = "yellow";
  ctx.fillText(`Score: ${score}`, 0, 25);

  var heart = '❤';
  var hearts = health > 0 ? heart.repeat(health) : " ";
  ctx.fillText("Helf:", canvas.width - 120, 25);
  ctx.fillStyle = "red";
  ctx.fillText(`${hearts}`, canvas.width - 60, 26);
}

function initialiseGame() {
  health = 3;
  elfX = (canvas.width-elfWidth)/2;
  bangTime = 0;
  score = 0;
  snowHeight = 6;
  timer = 0;
  spawnTimer = 50;
  gifts = [];
}

function initialiseSnow() {
  for (i=0; i<maxSnowflakes; i++) {
    var startY = -randomNumber(0, canvas.height);
    snowflakes[i] = {
      x: randomNumber(0, canvas.width-snowflakeSize),
      y: startY,
      startY: startY,
      colour: snowflakeColours[randomNumber(0,3)],
      radius: (Math.random() * 3 + 1),
      speed: randomNumber(snowflakeMinSpeed, snowflakeMaxSpeed)
    };
  }
}

function drawSnow() {
  for (i=0; i<maxSnowflakes; i++) {
    snowflakes[i].y+=snowflakes[i].speed;
    if (snowflakes[i].y>canvas.height) snowflakes[i].y = snowflakes[i].startY;
    ctx.beginPath();
    ctx.arc(snowflakes[i].x, snowflakes[i].y, snowflakes[i].radius, 0, 2 * Math.PI, false);
    ctx.fillStyle = snowflakes[i].colour;
    ctx.fill();
  }
}

function drawFloor() {
  var snowTopY = canvas.height - snowHeight;

  ctx.fillStyle = '#fff';
  ctx.beginPath();
  ctx.moveTo(0, snowTopY);
  ctx.lineTo(canvas.width, snowTopY);
  ctx.lineTo(canvas.width, canvas.height);
  ctx.lineTo(0, canvas.height);
  ctx.closePath();
  ctx.fill();
}

function drawSnowPerson() {
  var snowTopY = canvas.height - snowHeight;

  drawCircle("#fff", 100, snowTopY-20, 40);
  drawCircle("#fff", 100, snowTopY-70, 20);
  drawRectangle("#835C3B", 85, snowTopY-105, 30, 20);
  drawRectangle("#835C3B", 75, snowTopY-90, 50, 6);
  drawTriangle("#ffa500", 100, snowTopY-64, 7);
  drawCircle("#000", 93, snowTopY-76, 3);
  drawCircle("#000", 108, snowTopY-76, 3);
  drawCircle("#000", 100, snowTopY-40, 2);
  drawCircle("#000", 100, snowTopY-30, 2);
  drawCircle("#000", 100, snowTopY-20, 2);
}

function drawTriangle(color, x, y, height) {
  ctx.strokeStyle = ctx.fillStyle = color;
  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.lineTo(x - height, y - height);
  ctx.lineTo(x + height, y - height);
  ctx.fill();
}

function drawCircle(color, x, y, radius) {
  ctx.strokeStyle = ctx.fillStyle = color;
  ctx.beginPath();
  ctx.arc(x, y, radius, 0, Math.PI * 2, true);
  ctx.closePath();
  ctx.stroke();
  ctx.fill();
}

function drawRectangle(color, x, y, width, height) {
  ctx.strokeStyle = ctx.fillStyle = color;
  ctx.fillRect(x, y, width, height);
}

function randomNumber(low, high) {
  return Math.floor(Math.random() * high) + low; 
}

function makeColorGradient(frequency1, frequency2, frequency3,
                            phase1, phase2, phase3,
                            center, width, len) {
  var colours = [];

  for (var i = 0; i < len; ++i)
  {
    var r = Math.sin(frequency1*i + phase1) * width + center;
    var g = Math.sin(frequency2*i + phase2) * width + center;
    var b = Math.sin(frequency3*i + phase3) * width + center;
    colours.push(RGB2Color(r,g,b));
  }
  return colours;
}

function RGB2Color(r,g,b) {
  return '#' + byte2Hex(r) + byte2Hex(g) + byte2Hex(b);
}

function byte2Hex(n) {
  var nybHexString = "0123456789ABCDEF";
  return String(nybHexString.substr((n >> 4) & 0x0F,1)) + nybHexString.substr(n & 0x0F,1);
}

function setColourGradient() {
  center = 128;
  width = 127;
  steps = 6;
  frequency = 2*Math.PI/steps;
  return makeColorGradient(frequency,frequency,frequency,0,2,4,center,width,50);
}

function initialiseSpawnInterval() {
  if (gameMode === gameModes.PLAYING && spawnTimer>2) {
    spawnTimer--;
    spawnTimeChangeInterval -= 50;
  }
}

function setGameMode(mode) {
  gameMode = mode;
  timer=0;
}

function raiseSnow() {
  if (gameMode === gameModes.PLAYING && snowHeight < canvas.height) {
    snowHeight++;
  }
}

function setHighScore() {
  var currentHighScore = getHighScore();
  if (currentHighScore != -1 && score > currentHighScore) {
    localStorage.setItem("highScore", score);
  }
}

function getHighScore() {
  if (!localStorage) return -1;
  var highScore = localStorage.getItem("highScore");
  return highScore || 0;
}

titleColours = setColourGradient();
initialiseSnow();
setInterval(draw, 30);
setInterval(initialiseSpawnInterval, spawnTimeChangeInterval);
setInterval(raiseSnow, 666);

HTML code

<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Elf Gift Catch</title>

<link rel="stylesheet" href="css/style.css" rel="external nofollow" >#The code is too long if N characters are omitted</head>
<body>

<div id="wrapper">

	<canvas id="canvas" width="450" ​​height="540"></canvas>
	
</div>


  
</div>

<script src="js/script.js"></script>

</body>
</html>

Demonstration process

There are three packaged files, a CSS code, a JS code, and an HTML file. After packaging, you can run it directly by clicking the HTML file.

The above is the details of how to use JavaScript to implement a simple Christmas game. For more information about JavaScript Christmas games, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • Using JS to implement a rotating Christmas tree in HTML
  • Detailed explanation of dynamic Christmas tree through JavaScript
  • JavaScript flashing Christmas tree implementation code
  • JS practical object-oriented snake game example
  • HTML+CSS+JavaScript to create a simple tic-tac-toe game
  • Implementation of whack-a-mole game in JavaScript

<<:  How to remove the underline of a hyperlink using three simple examples

>>:  Comprehensive understanding of HTML basic structure

Recommend

Vue uses mockjs to generate simulated data case details

Table of contents Install mockjs in your project ...

Color matching techniques and effect display for beauty and styling websites

Color is one of the most important elements for a...

Let's talk about destructuring in JS ES6

Overview es6 adds a new way to get specified elem...

Explain MySQL's binlog log and how to use binlog log to recover data

As we all know, binlog logs are very important fo...

Detailed explanation of computed properties in Vue

Table of contents Interpolation Expressions metho...

Detailed explanation of JS browser storage

Table of contents introduction Cookie What are Co...

Detailed explanation of this pointing problem in JavaScript

Preface The this pointer in JS has always been a ...

JavaScript canvas to achieve meteor effects

This article shares the specific code for JavaScr...

How to display div on object without being blocked by object animation

Today I made a menu button. When you move the mous...

JavaScript implements the detailed process of stack structure

Table of contents 1. Understanding the stack stru...

How to use Docker Compose to implement nginx load balancing

Implement Nginx load balancing based on Docker ne...

Detailed explanation of nginx reverse proxy webSocket configuration

Recently, I used the webSocket protocol when work...

How to use @media in mobile adaptive styles

General mobile phone style: @media all and (orien...

Detailed explanation of common MySQL operation commands in Linux terminal

Serve: # chkconfig --list List all system service...

How to implement data persistence using the vuex third-party package

Purpose: Allow the state data managed in vuex to ...