这是一款横版跑酷类游戏,应为是JavaScript的所以不需要其他复杂的配置和环境,点击就能运行
线上试玩:http://longsong.games/newmoon
文末有代码地址
操作介绍:
↑ 跳跃 ↓ 坐下 跳砍 ← 往后跑 → 向前跑 enter 无敌翻滚 d 显示外形 q 重新开始游戏 energy 能量
下面是项目的目录:
其中主要的几个:
main.js:
import { Player } from './player.js'; import { InputHandle } from './input.js'; import { Background} from './background.js'; import { FlyingEnemy, ClimbEnemy, GroundEnemy} from './enemies.js'; import { UI } from './UI.js'; window.addEventListener('load', function(){ const canvas = document.getElementById('canvas1'); const ctx = canvas.getContext('2d'); canvas.width = 900; canvas.height = 500; let enemies = []; let score = 0; class Game{ constructor(width, height){ this.width = width; this.height = height; this.groundMargin = 40; this.speed = 0; this.maxSpeed = 5; this.background = new Background(this); this.player = new Player(this); this.input = new InputHandle(this); this.UI = new UI(this); this.enemies = []; this.particles = []; this.collisions = []; this.floatingMessages = []; this.maxParticles = 200; this.enemyTimer = 0; this.enemyInterval = 1000; this.debug = true; this.score = 0; this.energy = 0; this.time = 0; this.winningScore = 40; this.maxTime = 300000; this.fontColor = 'black'; this.player.currentState = this.player.state[0]; this.player.currentState.enter(); this.lives = 5; this.game = false; this.pan = 1; } update(deltaTime){ this.time += deltaTime; if (this.time > this.maxTime) this.gameOver = true; if (this.energy >= 0 ) this.energy += 1; if (this.energy < 0 && this.pan == 1 )this.energy += 1; this.background.update(); this.player.update(this.input.keys, deltaTime); if(this.enemyTimer > this.enemyInterval){ this.addEnemy(); this.enemyTimer =0; } else { this.enemyTimer += deltaTime; } //handleEnemies this.enemies.forEach(enemy =>{ enemy.update(deltaTime); }) //handle message this.floatingMessages.forEach(message =>{ message.update(deltaTime); }) //handle partyicles this.particles.forEach((particle, index) =>{ particle.update(); }); if (this.particles.length > this.maxParticles) { this.particles.length = this.maxParticles; } this.collisions.forEach((collision, index) => { collision.update(deltaTime); }); this.collisions = this.collisions.filter(collision => !collision.markedForDeletion); this.particles = this.particles.filter(particle => !particle.markedForDeletion); this.enemies = this.enemies.filter(enemy => !enemy.markedForDeletion); this.floatingMessages = this.floatingMessages.filter(message => !message.markedForDeletion); } draw(context){ this.background.draw(context); this.player.draw(context); this.enemies.forEach(enemy =>{ enemy.draw(context); }); this.particles.forEach(particle => { particle.draw(context); }); this.collisions.forEach(collision => { collision.draw(context); this.floatingMessages.forEach(message =>{ message.draw(context); }) }); this.UI.draw(context); } addEnemy(){ if (this.speed > 0 && Math.random() < 0.5) this.enemies.push(new GroundEnemy(this)); else if (this.speed > 0 ) this.enemies.push(new ClimbEnemy(this)); this.enemies.push(new FlyingEnemy(this)); console.log(this.enemies); } restartGame(){ this.player.restart(); this.background.restart(); this.enemies = []; this.gameOver = false; this.score = 0; this.energy = 0; this.lives = 5; this.time = 0; animate(0); } } const game = new Game(canvas.width, canvas.height); let lastTime = 0; function animate(timeStamp){ const deltaTime = timeStamp - lastTime; lastTime = timeStamp; ctx.clearRect(0, 0, canvas.width, canvas.height); game.update(deltaTime); game.draw(ctx); if (!game.gameOver) requestAnimationFrame(animate); } animate(0); })
复制
player.js
import { Sitting, Runing, Jumping, Falling, Rolling, Diving, Hit} from './playerStates.js'; import { CollisionAnimation } from './CollisionAnimation.js' import { FloatingMessage } from './floatingMessages.js' export class Player{ constructor(game){ this.game = game; this.width = 100; this.height = 91.3; this.x = 0; this.y = this.game.height - this.height - this.game.groundMargin; this.vy = 0; this.weight = 1; this.image = document.getElementById('player'); this.frameX = 0; //第几行图片 this.frameY = 0; //第几个状态 this.maxFrame; this.fps = 20; //帧数 this.frameInterval = 500/this.fps; this.f = 0; this.speed = 0; this.maxSpeed = 10; this.state = [new Sitting(this.game), new Runing(this.game), new Jumping(this.game), new Falling(this.game), new Rolling(this.game), new Diving(this.game), new Hit(this.game)]; this.currentState = null; } update(input, deltaTime){ //this.x++; //horizon movement this.checkCollision(); this.currentState.handleInput(input); this.x += this.speed; if (input.includes('ArrowRight') && this.currentState !== this.state[6]) this.speed = this.maxSpeed; else if (input.includes('ArrowLeft') && this.currentState !== this.state[6]) this.speed = -this.maxSpeed; else this.speed = 0; if (this.currentState === this.state[4]) this.game.energy -= 4; if (this.x <0) this.x = 0; if (this.x > this.game.width - this.width) this.x = this.game.width - this.width; //vertical movement this.y += this.vy; if (!this.onGround()) this.vy += this.weight; else this.vy = 0; //console.log(this.game.height - this.height); // sprite animation if (this.y > this.game.height - this.height - this.game.groundMargin) this.y = this.game.height - this.height - this.game.groundMargin; if (this.f > this.frameInterval){ this.f = 0; if (this.frameX < this.maxFrame) this.frameX++; else this.frameX = 0; } else { this.f =this.f + deltaTime; } //if (this.frameX < this.maxFrame) this.frameX++; //else this.frameX = 0; } restart(){ this.x = 0; this.y = this.game.height - this.height - this.game.groundMargin; } 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); } onGround(){ return this.y >= this.game.height - this.height - this.game.groundMargin; } setState(state, speed){ this.currentState = this.state[state]; this.game.speed = this.game.maxSpeed * speed; this.currentState.enter(); } checkCollision(){ this.game.enemies.forEach(enemy => { if (enemy.x < this.x + this.width && enemy.x + enemy.width > this.x && enemy.y < this.y + this.height && enemy.y + enemy.height > this.y ){ enemy.markedForDeletion = true; this.game.collisions.push(new CollisionAnimation(this.game, enemy.x + enemy.width * 0.5,enemy.y + enemy.height * 0.5 )); if (this.currentState === this.state[4] || this.currentState ===this.state[5]){ this.game.score++; this.game.energy += 100; this.game.floatingMessages.push(new FloatingMessage('+1', enemy.x, enemy.y,150, 50)); } else { this.setState(6, 0); this.game.score -=5 ; this.game.lives --; if (this.game.lives <= 0) this.game.gameOver = true; } //collosion detected } else { //no collision } }); } }
复制
playerState.js
import { Dust,Fire,Splash } from './particles.js' const state = { //状态 SITTING: 0, RUNNING: 1, JUMPING: 2, FALLING: 3, ROLLING: 4, DIVING: 5, HIT: 6 } class State { constructor(state, game){ this.state = state; this.game = game; } } export class Sitting extends State { constructor(game){ super('SITTING', game); } enter(){ this.game.player.frameX = 0; this.game.player.frameY = 5; this.game.player.maxFrame = 4; } handleInput(input){ //对初始状态的输入 if (input.includes('ArrowLeft') || input.includes('ArrowRight')){ this.game.player.setState(state.RUNNING, 1); } else if (input.includes('ArrowUp')){ this.game.player.setState(state.JUMPING, 1); } else if (input.includes('Enter') && this.game.energy >= 0){ this.game.player.setState(state.ROLLING, 2); } } } export class Runing extends State { //奔跑 constructor(game){ super('RUNNING', game); } enter(){ this.game.player.frameX = 0; this.game.player.frameY = 3; this.game.player.maxFrame = 8; } handleInput(input){ if (input.includes('Enter')) { this.game.pan = 0; } else this.game.pan = 1; this.game.particles.unshift(new Dust(this.game, this.game.player.x + this.game.player.width * 0.7, this.game.player.y + this.game.player.height)); if (input.includes('ArrowDown')){ this.game.player.setState(state.SITTING, 0); } else if (input.includes('ArrowUp')){ this.game.player.setState(state.JUMPING, 1); }else if (input.includes('Enter')&& this.game.energy >= 0){ this.game.player.setState(state.ROLLING, 2); } } } export class Jumping extends State { //跳远 constructor(game){ super('JUMPING',game); } enter(){ if (this.game.player.onGround()) this.game.player.vy -= 27; this.game.player.frameX = 0; this.game.player.frameY = 1; this.game.player.maxFrame = 6; } handleInput(input){ if (input.includes('Enter')) { this.game.pan = 0; } else this.game.pan = 1; if (this.game.player.vy > this.game.player.weight){ this.game.player.setState(state.FALLING, 1); }else if (input.includes('Enter') && this.game.energy >= 0){ this.game.player.setState(state.ROLLING, 2); }else if (input.includes('ArrowDown')){ this.game.player.setState(state.DIVING, 0); } } } export class Falling extends State { //掉落 constructor(game){ super('FALLING', game); } enter(){ this.game.player.frameX = 0; this.game.player.frameY = 2; this.game.player.maxFrame = 6; } handleInput(input){ if (input.includes('Enter')) { this.game.pan = 0; } else this.game.pan = 1; if (this.game.player.onGround()){ this.game.player.setState(state.RUNNING, 1); }else if (input.includes('ArrowDown')){ this.game.player.setState(state.DIVING, 0); }else if (input.includes('Enter') && this.game.energy >= 0){ this.game.player.setState(state.ROLLING, 2); } } } export class Rolling extends State { //冲刺 constructor(game){ super('ROLLING', game); } enter(){ this.game.player.frameX = 0; this.game.player.frameY = 6; this.game.player.maxFrame = 6; } handleInput(input){ this.game.particles.unshift(new Fire(this.game, this.game.player.x + this.game.player.width * 0.5, this.game.player.y + this.game.player.height * 0.5)); if (this.game.energy < 0){ if (this.game.player.onGround()){ this.game.player.setState(state.RUNNING, 1); } else if (!this.game.player.onGround()){ this.game.player.setState(state.FALLING, 1); } else if ( input.includes('ArrowUp') && this.game.player.onGround()){ this.game.player.vy -= 27; } else if (input.includes('ArrowDown') && !this.game.player.onGround()) { this.game.player.vy -= 27; } }else{ if (!input.includes('Enter') && this.game.player.onGround()){ this.game.player.setState(state.RUNNING, 1); } else if (!input.includes('Enter') && !this.game.player.onGround()){ this.game.player.setState(state.FALLING, 1); } else if (input.includes('Enter') && input.includes('ArrowUp') && this.game.player.onGround()){ this.game.player.vy -= 27; } else if (input.includes('ArrowDown') && !this.game.player.onGround()) { this.game.player.vy -= 27; } } } } export class Diving extends State { //急速下坠 constructor(game){ super('DIVING', game); } enter(){ this.game.player.frameX = 0; this.game.player.frameY = 6; this.game.player.maxFrame = 6; this.game.player.vy = 15; } handleInput(input){ if (input.includes('Enter')) { this.game.pan = 0; } else this.game.pan = 1; this.game.particles.unshift(new Fire(this.game, this.game.player.x + this.game.player.width * 0.5, this.game.player.y + this.game.player.height * 0.5)); if (this.game.player.onGround()){ this.game.player.setState(state.RUNNING, 1); for(let i = 0; i < 30;i++){ this.game.particles.unshift(new Splash(this.game, this.game.player.x + this.game.player.width * 0.5, this.game.player.y + this.game.player.height * 0.5)); } } else if (input.includes('Enter') && !this.game.player.onGround()){ this.game.player.setState(state.ROLLING, 2); } } } export class Hit extends State { //眩晕 constructor(game){ super('HIT', game); } enter(){ this.game.player.frameX = 0; this.game.player.frameY = 4; this.game.player.maxFrame = 10; } handleInput(input){ if (this.game.player.frameX >= 10 && this.game.player.onGround() ){ this.game.player.setState(state.RUNNING, 1); } else if (this.game.player.frameX >= 10 && !this.game.player.onGround()){ this.game.player.setState(state.FALLING, 1); } } }
复制
代码库:
https://github.com/longsongline/NewMoonDog/https://github.com/longsongline/NewMoonDog/
哪里看不懂的可以在下面留言,或者私信问我
图片我都上传到自己的服务器上上了,所以代码库里没有图片
参考:十个小时教程 ,喜欢的可以自己跟着教程做出一个差不多样子的
https://www.youtube.com/watch?v=GFO_txvwK_c&list=WL&index=12