JS小游戏-像素鸟#源码#Javascript

news2025/3/14 11:33:25

1、游戏图片

像素鸟小游戏
在这里插入图片描述

2、HTML部分

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body{
            margin: 0;
        }
        .game{
            position: relative;
            width: 800px;
            height: 600px;
            margin: 0 auto;
            overflow: hidden;
        }
        .sky {
            position: absolute;
            width: 200%;
            height: 100%;
            background-image: url('./img/sky.png');
            margin: 0 auto;
        }

        .game .bird {
            background: url("./img/bird.png");
            position: absolute;
            width: 33px;
            height: 26px;
            left: 150px;
            top: 150px;
        }

        .game .bird.swing1{
            background-position: -8px -10px;
        }

        .game .bird.swing2{
            background-position: -60px -10px;
        }

        .game .bird.swing3{
            background-position: -113px -10px;
        }
        .pipeDown{
            position: absolute;
            background-image: url('./img/pipeUp.png');
            width: 52px;
            height: 100px;
            left: 500px;
            bottom: 112px;
        }

        .pipeUp{
            position: absolute;
            background-image: url('./img/pipeDown.png');
            background-position: bottom;
            width: 52px;
            height: 100px;
            left: 500px;
            top: 0;
        }
        .ground{
            position: absolute;
            background-image: url('./img/land.png');
            width: 200%;
            height: 112px;
            left: 0;
            bottom: 0;
        }

        .score{
            position: absolute;
            width: 100px;
            height: 36px;
            background-color: lightblue;
            right: 0;
            top: 0;
            text-align: center;
            line-height: 36px;
            font-size: 24px;
            z-index: 100;
        }
        p{
            text-align: center;
        }


    </style>
</head>
<body>
    <div class="game">
        <div class="sky"></div>
        <div class="bird swing1"></div>
        <div class="ground"></div>
        <div class="score">0</div>
    </div>
    <p>按w或者按上开始游戏</p>

    <script src="./JS/Rectangle.js"></script>
    <script src="./JS/Sky.js"></script>
    <script src="./JS/Land.js"></script>
    <script src="./JS/Bird.js"></script>
    <script src="./JS/Pipe.js"></script>
    <script src="./JS/Game.js"></script>
</body>
</html>

3、JS部分

baseGame class
/**
 * 基础的游戏类
 * 属性: 宽度 高度、横坐标、纵坐标、横向速度、纵向速度、对应的dom元素
 */
class Rectangle {
    constructor(width,height,x,y,vx,vy,dom){
        this.width = width;
        this.height = height;
        this.x = x;
        this.y = y;
        this.vx = vx;
        this.vy = vy;
        this.dom = dom;
        this.render();
    }

    /**
     * 渲染
     */
    render(){
        this.dom.style.width = this.width + "px";
        this.dom.style.height = this.height + "px";
        this.dom.style.left = this.x + "px";
        this.dom.style.top = this.y + "px";
    }
    onMove(){

    }
    /**
     *  在duration时间下物体移动
     * @param {number} duration  间隔
     */
    move(duration){
        this.x += this.vx * duration;
        this.y += this.vy * duration;
        if(this.onMove) this.onMove();
        this.render();
    }
}
sky ground class
const skyDom = document.querySelector('.sky');
skyStyle = getComputedStyle(skyDom);
const widthSky = parseFloat(skyStyle.width);
const heightSky = parseFloat(skyStyle.width);

class Sky extends Rectangle{
    constructor(){
        super(widthSky, heightSky, 0, 0, -100, 0, skyDom);
    }
    onMove(){
        if(this.x <= -widthSky / 2) {
            this.x = 0;
        }
    }
}
const landDom = document.querySelector('.ground');
landStyle = getComputedStyle(landDom);
const widthLand = parseFloat(landStyle.width);
const heightLand = parseFloat(landStyle.width);


class Land extends Rectangle{
    constructor(){
        super(widthLand, heightLand, 0, 488, -100, 0, landDom);
    }

    onMove(){
        if(this.x <= -widthLand / 2) {
            this.x = 0;
        }
    }
}
bird class
const birdDom = document.querySelector('.bird');
birdStyle = getComputedStyle(birdDom);
const widthBird = parseFloat(birdStyle.width);
const heightBird = parseFloat(birdStyle.height);

class Bird extends Rectangle{
    gravity = 1000;   
    constructor(){
        super(widthBird, heightBird, 150, 200, 0, 100, birdDom);
        this.swingState = 1;
        this.bindEvent();
    }
    
    // 綁定鼠標按下
    bindEvent(){
        document.addEventListener('keydown', (e) => {
            if(e.key === 'w' || e.key === 'ArrowUp'){
                this.vy += -550;
            }
        })
        this.startSwing();
    }

    // 小鳥扇翅膀
    startSwing(){
        if(this.timer){
            return ;
        }
        this.timer = setInterval( () => {
            birdDom.classList.remove('swing'+this.swingState);
            this.swingState = (++this.swingState % 3) + 1;
            birdDom.classList.add('swing'+this.swingState);
        },300)
    }
    stopSwing(){
        clearInterval(this.timer);
        this.timer = null;
    }

    onMove(){
        if(this.y >= 463) {
            this.y = 463;
            this.vy =0;
        }
        if(this.y <= 0 ){
            this.y = 0;
            this.vy = 0;
        }
    }

    move(duration){
        super.move(duration);
        this.vy += this.gravity * duration;
    }

}
pipe class
const game = document.querySelector('.game');
const gameWidth = game.clientWidth;
class Pipe extends Rectangle{
    isExited = true;
    constructor(height, top, speed, dom){
        super(52, height, gameWidth, top, speed, 0, dom);
    }
    onMove(){

        if(this.x < -this.width){
            this.dom.remove();
            this.isExited = false;
        }
    }

    
}

function getRandomNumber(min, max){
    return Math.floor(Math.random() * (max - min)) + min;
}

class PipePare{
    stopTimer = null;
    
    constructor(speed){
        this.up = document.createElement('div');
        this.down = document.createElement('div');
        this.up.classList.add('pipeUp');
        this.down.classList.add('pipeDown');
        game.appendChild(this.up);
        game.appendChild(this.down);

        this.spaceHeihgt = 150;  // 柱子之間的空隙 
        const fristPipeHeight = getRandomNumber(0, 488-150);

        this.upPipe = new Pipe(fristPipeHeight, 0, speed, this.up);
        this.downPipe = new Pipe(338 - fristPipeHeight, 150 + fristPipeHeight, speed, this.down);
    }
    stop(){
        if(this.stopTimer){
            clearInterval(this.stopTimer);
            this.stopTimer = null;
        }
        this.down.remove();
        this.up.remove();
    }

    move(duration){
        this.stopTimer = setInterval( () => {
            this.upPipe.move(duration);
            this.downPipe.move(duration);
        },10)
    }

    isCollision(bird){
        const birdStyle = getComputedStyle(document.querySelector('.bird'))
        let y = Number.parseInt(birdStyle.top);
        if(this.upPipe.x < bird.x + bird.width && this.upPipe.x > bird.x){
            return y < this.upPipe.height || y + bird.height > this.upPipe.height + this.spaceHeihgt;
        }
    }
}

class GamePipePair{
    pipeTimer = null;
    pipeArr = [];  // 用于显示的管道数组
    // 记录小鸟越过的数组
    scoreArr = [];
    constructor(speed){
        this.speed = speed;
        this.pair = new PipePare(speed);
        this.init();
    }

    init(){
        this.pipeTimer = setInterval( ()=> {
            let tmp = new PipePare(this.speed);
            tmp.move(0.01);
            this.pipeArr.push(tmp);
            this.scoreArr.push(tmp);
        }, 2000) 
    }

    getScore(bird){
        return this.scoreArr.filter(item => item.upPipe.x <= bird.x).length;
    }

    stop(){
        this.pipeArr.forEach(item => {
            item.stop();
        })
        if(this.pipeTimer){
            clearInterval(this.pipeTimer);
            this.pipeTimer = null;
        }
    }

    collisionDetection(bird){  // 小鸟对象传入
        this.pipeArr = this.pipeArr.filter(item => item.upPipe.isExited); // 过滤掉了不存在的
        // 检查小鸟是否碰撞到柱子
        for(let i = 0 ;i < this.pipeArr.length;i++){
            if(this.pipeArr[i].isCollision(bird)){
                return true;
            }
        }
        return false;
    }
    
}
game class
class Game {
    score = 0;
    land;
    sky;
    bird;
    backgroundTimer = null;
    pipeController = null;
    
    constructor(){
        this.land = new Land();
        this.sky = new Sky();
        this.bird = new Bird();
        this.state = 0;   // 0 遊戲結束  1遊戲開始進行中
        this.init();   
    }

    init(){
        document.onkeydown =  (e) => {
            if((e.key === 'w' || e.key === 'ArrowUp') && this.state === 0){
                console.log('開始遊戲');
                this.state = 1;
                this.startGame();
            }
        }
    }

    startGame(){
        this.pipeController = new GamePipePair(-100);
        if(this.backgroundTimer) return ;
        this.backgroundTimer = setInterval(() => {
            this.land.move(0.01);
            this.sky.move(0.01);
            this.bird.move(0.01);
            this.updateScore();
            if(this.pipeController){
                if(this.pipeController.collisionDetection(this.bird)){
                    this.endGame();
                    console.log('game ended');
                }
            }
        }, 10)


    }

    updateScore(){
        const score = document.querySelector('.score');
        this.score = this.pipeController.getScore(this.bird)
        score.innerHTML = this.score;
    }

    endGame(){
        if(this.backgroundTimer && this.state === 1){
            this.pipeController.stop();
            this.state = 0;
            this.bird.stopSwing();
            clearInterval(this.backgroundTimer);
            this.backgroundTimer = null;
            document.onkeydown = null;
            if(confirm(`游戏结束!! 
                你最后的得分是${this.score}分
                你想要再玩一局嘛 想玩点确定哦!!!
                `)){
                    this.init();
                }
        }
    }

}

const birdGame = new Game();

4、源码+静态资源

像素鸟源码地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1850779.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

操作系统:高效、稳定的承上启下

标题&#xff1a;操作系统&#xff1a;高效、稳定的承上启下 水墨不写bug &#xff08;图片来源于网络&#xff09; 目录 一、初识操作系统 第一个操作系统&#xff1a;Uinx Uinx的商业化 Linux&#xff1a;横空出世 二、如何在Windows上使用Linux 正文开始&#xff1a;…

2023年JCR影响因子正式发布,点击查看能源与燃料领域期刊变化【持续更新02】

2024年6月20日&#xff0c;科睿唯安发布了2024年度《期刊引证报告》(Journal Citation Reports&#xff0c;JCR)&#xff0c;报告覆盖全面的高质量期刊资源&#xff0c;提供了丰富的数据、指标和分析。今年JCR的最大变化为&#xff1a;把属于不同数据库&#xff0c;但属于同一学…

移动端的HSR技术

overdraw问题&#xff1a; overdraw顾名思义就是过度绘制&#xff0c;就是在渲染过程中**绘制一帧FBO&#xff08;或者RenderTarget&#xff09;**超过一次相同像素的现象!这个是CG的问题&#xff01;特别在是用来大量的透明混合的情况下会产生的&#xff0c;当然客户端andrio…

【代码随想录】【算法训练营】【第45天】 [198]打家劫舍 [213]打家劫舍II [337]打家劫舍III

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 45&#xff0c;周五&#xff0c;坚持不了一点~ 题目详情 [198] 打家劫舍 题目描述 198 打家劫舍 解题思路 前提&#xff1a; 思路&#xff1a; 重点&#xff1a; 代码实现 C语言 虚拟头…

1027. 方格取数

Powered by:NEFU AB-IN Link 文章目录 1027. 方格取数题意思路代码 1027. 方格取数 题意 某人从图中的左上角 A 出发&#xff0c;可以向下行走&#xff0c;也可以向右行走&#xff0c;直到到达右下角的 B 点。 在走过的路上&#xff0c;他可以取走方格中的数&#xff08;取…

MySQL数据库中的索引知识

MySQL数据库中索引的作用是用来加快数据的查询速度。 索引 index&#xff08;表的层面&#xff09; 在数据库中使用select来查询数据的时候会一条一条得去查询符合要求的数据&#xff0c;而索引就相当于在这张表中依据某一个字段的数值给这张表的数据创建了一个目录。目录帮…

NSIS 入门教程 (一)

介绍 大多数应用程序都附带一个安装程序&#xff0c;它将所需的文件复制到正确的文件夹中&#xff0c;创建注册表项&#xff0c;并提供卸载例程以&#xff08;希望&#xff09;从计算机中彻底删除应用程序. 有多种解决方案可以为自主开发的应用程序配备安装程序。除了Install …

服务器安装JDK,Maven等常用环境

生产环境部署服务器需要安装一些常用工具&#xff0c;下面我就把常用的jdk&#xff0c;maven&#xff0c;node&#xff0c;git的安装方法和步骤演示 一、安装JDK环境 执行如下命令&#xff0c;安装JDK,所有命令都是 复制&#xff0c;粘贴&#xff0c;回车 yum install -y jav…

Apple - Secure Coding Guide

本文翻译整理自&#xff1a;Secure Coding Guide https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Introduction.html#//apple_ref/doc/uid/TP40002477-SW1 文章目录 一、安全编码指南简介1、概览黑客和攻击者没有平台是免疫…

并行计算之SIMD与SPMD

SIMD (Single Instruction Multiple Data) SIMD&#xff0c;也就是单指令多数据计算&#xff0c;一条指令可以处理多个数据。通过向量寄存器存储多个数据元素&#xff0c;并使用单条指令同时对这些数据元素进行处理&#xff0c;从而提高了计算效率。 代码示例&#xff1a; fl…

【数据结构】顺序表实操——通讯录项目

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

对比学习

对比学习基本概念 对比学习通过对比数据对的“相似”或“不同”以获取数据的高阶信息。 由同一张原始图片扩增而来的两张新的图片&#xff0c;叫做Positive Pairs。将这两张图片送入深度学习模型中&#xff0c;我们希望深度学习模型学习到这两个图像是相似的。 由不同原始图…

【尚庭公寓SpringBoot + Vue 项目实战】移动端找房功能(二十一)

【尚庭公寓SpringBoot Vue 项目实战】移动端找房功能&#xff08;二十一&#xff09; 文章目录 【尚庭公寓SpringBoot Vue 项目实战】移动端找房功能&#xff08;二十一&#xff09;1、业务介绍2、接口开发2.1、地区信息2.2、获取全部支付方式列表2.3、房间信息2.2.1. 根据条…

SpringCloud中Eureka和Nacos的区别和各自的优点

Eureka注册中心 Eureka作为一个注册中心&#xff0c;服务提供者把服务注册到注册中心&#xff0c;服务消费者去注册中心拉取信息&#xff0c; 然后通过负载均衡得到对应的服务器去访问。 服务提供者每隔30s向注册中心发送请求&#xff0c;报告自己的状态&#xff0c;当超过一定…

【网络安全的神秘世界】关于Linux中一些好玩的字符游戏

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 佛祖保佑 把 motd 通过xtp拖到Linux中 liyangUbuntu2204:~$ cp motd /etc/motd #一定要放在etc下 liyangUbuntu2204:~$ exi…

windows设置开机启动项

将文件放到下面路径即可实现每次开机启动 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup

数据分析-相关性

0、提高数据样本质量 首先是确保数据采集的准确性与可靠性&#xff0c;也就是如何降低数据误差 系统误差是由测量工具不精确和测量方法选择不当造成的。这类误差我们可以通过校准工具或者选择更合适的测量方法来消除&#xff1b;随机误差是由环境因素等外部不可控原因导致的&…

RStudio Desktop 安装

RStudio 下载 macOS 安装 RStudio Desktop 打开报错 R not found Could not locate an R installation on the system.安装R https://cloud.r-project.org/bin/macosx/安装 R-4.4.1-arm64.pkg 成功打开 参考 RStudio 桌面版安装R

React的Redux的状态管理

步骤 1.创建新项目 npx create-react-app react-redux 2.安装配套工具 npm i reduxjs/toolkit react-redux 3.启动项目 npm run start 4.在src目录下创建store文件夹 5.在store文件夹下创建modules文件夹 6.在store文件夹里创建index.js文件 7.在counterStore.js文件…

Redis的实战常用一、验证码登录(解决session共享问题)(思路、意识)

一、基于session实现登录功能 第一步&#xff1a;发送验证码&#xff1a; 用户在提交手机号后&#xff0c;会校验手机号是否合法&#xff1a; 如果不合法&#xff0c;则要求用户重新输入手机号如果手机号合法&#xff0c;后台此时生成对应的验证码&#xff0c;同时将验证码进行…