NewMoonDog 影子狗 基于JavaScript的跑酷游戏,复制就能玩

138 阅读2分钟

这是一款横版跑酷类游戏,应为是JavaScript的所以不需要其他复杂的配置和环境,点击就能运行 线上试玩: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); } } }

代码库: github.com/longsonglin… github.com/longsonglin…

哪里看不懂的可以在下面留言,或者私信问我 图片我都上传到自己的服务器上上了,所以代码库里没有图片

参考:十个小时教程 ,喜欢的可以自己跟着教程做出一个差不多样子的

www.youtube.com/watch?v=GFO… ———————————————— 版权声明:本文为CSDN博主「long_songs」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:blog.csdn.net/long_songs/…