21xrx.com
2024-12-23 02:46:17 Monday
登录
文章检索 我的文章 写文章
Javascript游戏源码分享及实例演练
2023-06-15 17:49:28 深夜i     --     --
Javascript游戏开发 Canvas 游戏源码

近年来Javascript游戏开发越来越热门,大量的游戏工具和框架涌现,吸引了越来越多的游戏爱好者和开发者。本文将分享一些常用的Javascript游戏源码,并结合实例演练,为大家展现Javascript游戏开发的魅力。

1. 翻转拼图游戏源码

这是一款经典的翻转拼图游戏,适合初学者练手,也能培养玩家分析和思考能力。


const game = document.querySelector('#game');

const rows = 4;

const cols = 4;

const pieces = rows * cols;

let empty;

let prevEmpty;

let moves = 0;

const board = Array(rows)

 .fill()

 .map((_, row) =>

  Array(cols)

   .fill()

   .map((_, col) => {

    const piece = row * cols + col + 1;

    const tile = document.createElement('div');

    tile.id = `piece-${piece}`;

    tile.className = 'tile';

    tile.style.backgroundImage = `url('images/nature.jpg')`;

    tile.style.backgroundPosition = `${-col * 100}% ${-row * 100}%`;

    tile.style.top = `${row * 100}px`;

    tile.style.left = `${col * 100}px`;

    tile.dataset.row = row;

    tile.dataset.col = col;

    tile.addEventListener('click', e => movePiece(e.target));

    tile.addEventListener('mousemove', e => swapPrevEmpty(e.target));

    game.appendChild(tile);

    return tile;

   })

 );

board[rows - 1][cols - 1].remove();

function movePiece(tile) {

 const row = tile.dataset;

 const distance = Math.abs(parseInt(row) - empty.row) + Math.abs(parseInt(col) - empty.col);

 if (distance === 1) {

  const tmp = tile.style.top;

  tile.style.top = empty.top;

  empty.top = tmp;

  const tmp2 = tile.style.left;

  tile.style.left = empty.left;

  empty.left = tmp2;

  [empty.row, tile.dataset.row] = [tile.dataset.row, empty.row];

  [empty.col, tile.dataset.col] = [tile.dataset.col, empty.col];

  moves++;

  checkWin();

 }

}

function swapPrevEmpty(tile) {

 const col = tile.dataset;

 const distance = Math.abs(parseInt(row) - empty.row) + Math.abs(parseInt(col) - empty.col);

 if (distance === 1 && tile !== prevEmpty)

  prevEmpty.style.borderStyle = 'solid';

  prevEmpty = tile;

  tile.style.borderStyle = 'dotted';

 

}

function checkWin() {

 const positions = board.flat().map(tile => `${tile.dataset.row},${tile.dataset.col}`).join('|');

 const pattern = new RegExp(`0,0|(${pieces - 1}),(${pieces - 1})|-1`);

 if (positions.match(pattern)) return;

 alert(`Congratulations! You solved the puzzle in ${moves} moves!`);

}

function random(start, end) {

 return Math.floor(Math.random() * (end - start + 1) + start);

}

function shuffle() {

 for (let i = 0; i < pieces - 1; i++) {

  const row = Math.floor(i / cols);

  const col = i % cols;

  const row: emptyRow = empty;

  const distance = Math.abs(row - emptyRow) + Math.abs(col - emptyCol);

  if (distance > 1) continue;

  const piece = document.querySelector(`#piece-${i + 1}`);

  piece.style.top = `${emptyRow * 100}px`;

  piece.style.left = `${emptyCol * 100}px`;

  piece.dataset.row = emptyRow;

  piece.dataset.col = emptyCol;

  [empty.pos, piece.pos] = [piece.pos, empty.pos];

  [empty.row, piece.dataset.row] = [piece.dataset.row, empty.row];

  [empty.col, piece.dataset.col] = [piece.dataset.col, empty.col];

 }

 moves = 0;

 prevEmpty = empty;

}

function newGame() {

 empty = { pos: pieces, row: rows - 1, col: cols - 1, top: `${(rows - 1) * 100}px`, left: `${(cols - 1) * 100}px` };

 shuffle();

}

newGame();

2. 经典飞行射击游戏源码

这是一款经典的飞行射击游戏,使用HTML5 Canvas实现,适合中高级开发者练习。


const canvas = document.querySelector('canvas');

const ctx = canvas.getContext('2d');

canvas.height = 400;

canvas.width = 800;

const ship =

 height: 20;

const bullets = [];

const enemies = [];

const deaths = [];

class Bullet {

 constructor(x, y)

  this.x = x;

  this.y = y;

  this.height = 5;

  this.width = 5;

  this.speed = 10;

 

 move()

  this.y -= this.speed;

 

}

class Enemy {

 constructor(x, y)

  this.x = x;

  this.y = y;

  this.speed = 4;

  this.height = 20;

  this.width = 40;

 

 move() {

  this.y += this.speed;

 }

}

function fire() {

 const bullet = new Bullet(ship.x + ship.width / 2, ship.y - ship.height / 2);

 bullets.push(bullet);

}

function spawnEnemy() {

 const margin = 50;

 const minWidth = 60;

 const maxWidth = canvas.width - minWidth - margin;

 const x = Math.floor(Math.random() * (maxWidth - minWidth + 1) + minWidth);

 const enemy = new Enemy(x, -20);

 enemies.push(enemy);

}

function detectCollisions() {

 bullets.forEach(bullet => {

  enemies.forEach(enemy => {

   if (

    bullet.x < enemy.x + enemy.width &&

    bullet.x + bullet.width > enemy.x &&

    bullet.y < enemy.y + enemy.height &&

    bullet.y + bullet.height > enemy.y

   ) {

    deaths.push(enemy);

    deaths.push(bullet);

   }

  });

 });

 deaths.forEach(death => {

  enemies.splice(enemies.indexOf(death), 1);

  bullets.splice(bullets.indexOf(death), 1);

 });

 deaths.length = 0;

}

function gameOver() {

 clearInterval(interval);

 ctx.fillStyle = 'black';

 ctx.font = 'bold 64px Arial';

 ctx.fillText('GAME OVER', canvas.width / 2 - 180, canvas.height / 2);

}

function draw() {

 ctx.clearRect(0, 0, canvas.width, canvas.height);

 ctx.fillStyle = 'white';

 ctx.fillRect(ship.x, ship.y, ship.width, ship.height);

 bullets.forEach(bullet => {

  ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);

  bullet.move();

 });

 enemies.forEach(enemy => {

  ctx.fillStyle = 'red';

  ctx.fillRect(enemy.x, enemy.y, enemy.width, enemy.height);

  enemy.move();

 });

 if (enemies.length < 10) spawnEnemy();

 detectCollisions();

 if (ship.x + ship.vx >= 0 && ship.x + ship.vx <= canvas.width - ship.width) ship.x += ship.vx;

 requestAnimationFrame(draw);

}

document.addEventListener('keydown', e => {

 if (e.keyCode === 37) ship.vx = -ship.speed;

 if (e.keyCode === 39) ship.vx = ship.speed;

 if (e.keyCode === 32) fire();

});

document.addEventListener('keyup', e => {

 if (e.keyCode === 37 || e.keyCode === 39) ship.vx = 0;

});

let interval = setInterval(function() {

 let direction = 1;

 if (enemies.length > 0) {

  if (enemies[0].y > canvas.height - 60) gameOver();

  enemies.forEach(enemy => {

   if (enemy.x + enemy.width > canvas.width || enemy.x < 0) direction = -1;

   enemy.x += enemy.speed * direction;

  });

 }

}, 1000 / 60);

draw();

3. 伪3D赛车游戏源码

这是一款炫酷的伪3D赛车游戏,使用Canvas动态绘制道路和赛车,适合高级开发者练习。


const canvas = document.querySelector('canvas');

const ctx = canvas.getContext('2d');

canvas.height = 400;

canvas.width = 800;

const road =

 lanes: 4;

const car = {

 x: road.x + road.width / 2 - 10,

 y: road.height - 20,

 width: 20,

 height: 40,

 speed: 0,

 rotation: 0,

 maxSpeed: 8,

 minSpeed: -4,

 acceleration: 0.2,

 braking: 0.5,

 steerAngle: 0.1,

 steerLimit: 0.15

};

const coefs =

 curve: 0.5;

let trackLength = 2000;

let segments = [];

for (let i = 0; i < trackLength; i++) {

 let segment = {

  x: 0,

  y: 0,

  z: i * road.width / trackLength,

  curve: 0,

  hill: 0

 };

 if (i % 9 === 0) segment.curve = random(-1, 2);

 if (i % 18 === 0) segment.hill = random(-1, 2);

 segments.push(segment);

}

function random(start, end) {

 return Math.floor(Math.random() * (end - start + 1) + start);

}

function updateSpeed() {

 if (car.speed < car.maxSpeed && car.acceleration > 0) car.speed += car.acceleration;

 if (car.speed > car.minSpeed && car.acceleration < 0) car.speed += car.acceleration;

 if (car.speed > 0 && car.braking > 0) car.speed -= car.braking;

 if (car.speed < 0 && car.braking < 0) car.speed -= car.braking;

 if (Math.abs(car.speed) < 0.1) car.speed = 0;

}

function updatePosition() {

 let segmentIndex = Math.floor(car.y / road.laneWidth) % segments.length;

 let currentSegment = segments[segmentIndex];

 let nextSegment = segments[(segmentIndex + 1) % segments.length];

 let distance = currentSegment.z + car.speed;

 let height = interpolate(currentSegment.hill, nextSegment.hill, distance, road.length);

 let curve = interpolate(currentSegment.curve, nextSegment.curve, distance, road.length);

 let x = road.x + curve;

 let y = car.y + car.speed;

 let rotation = car.steerAngle * car.speed * curve * 100;

 car.x = x - rotation;

 car.rotation = rotation;

 car.y = y;

}

function interpolate(a, b, distance, roadLength) {

 let result = a + (b - a) * distance / roadLength;

 return result;

}

function newSegment(segment) {

 if (segment.z < -road.width) {

  let index = segments.indexOf(segment);

  let count = segments.length - index;

  let slope = random(1, 4) === 1 ? random(1, 3) * 1.5 : 0;

  let curve = random(-1, 2);

  let hill = random(-1, 3);

  for (let i = 0; i < count; i++) {

   segments.push({

    x: 0,

    y: 0,

    z: segments.length * road.width / trackLength,

    slope: slope,

    curve: curve,

    hill: hill

   });

  }

  trackLength += count;

  segments.splice(0, count);

 }

}

function draw() {

 ctx.clearRect(0, 0, canvas.width, canvas.height);

 updateSpeed();

 updatePosition();

 for (let i = 0; i < segments.length; i++) {

  let segment = segments[i];

  segment.x = road.x + segment.curve;

  segment.y = i * road.laneWidth - car.y % road.laneWidth + height;

  segment.height = road.laneWidth;

  segment.width = road.width;

  segment.color = i % 2 === 0 ? 'lightgray' : 'darkgray';

  newSegment(segment);

  drawSegment(segment);

 }

 drawCar();

 requestAnimationFrame(draw);

}

function drawSegment(segment) {

 ctx.fillStyle = segment.color;

 ctx.fillRect(segment.x, segment.y, segment.width, segment.height);

}

function drawCar() {

 ctx.fillStyle = 'red';

 ctx.translate(car.x + car.width / 2, car.y + car.height / 2);

 ctx.rotate(car.rotation);

 ctx.fillRect(-car.width / 2, -car.height / 2, car.width, car.height);

 ctx.rotate(-car.rotation);

 ctx.translate(-car.x - car.width / 2, -car.y - car.height / 2);

}

document.addEventListener('keydown', e => {

 if (e.keyCode === 38)

  car.acceleration = 0.2;

  car.braking = 0;

 

 if (e.keyCode === 40)

  car.braking = 0.2;

  car.acceleration = 0;

 

 if (e.keyCode === 37) car.steerAngle = -car.steerLimit;

 if (e.keyCode === 39) car.steerAngle = car.steerLimit;

});

document.addEventListener('keyup', e => {

 if (e.keyCode === 38)

  car.acceleration = 0;

  car.braking = 0.05;

 

 if (e.keyCode === 40)

  car.braking = 0;

  car.acceleration = -0.1;

 

 if (e.keyCode === 37 || e.keyCode === 39) car.steerAngle = 0;

});

draw();

  
  

评论区

{{item['qq_nickname']}}
()
回复
回复