IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Web中期项目 - 拳皇 -> 正文阅读

[JavaScript知识库]Web中期项目 - 拳皇

前言

? ? ? ? ? Acwing Web应用课 拳皇 中期项目!

一、原理简介

  1. 一个物体移动的基本逻辑
    浏览器默认每秒刷新 60 次,每次单独计算一下物体新的位置,然后刷新出来
  2. 运动方式
    • 平面移动
    • 二维运动:坐标(x, y),宽高,vx:x 方向运动速度,vy:y方向运动速度
    • 每次水平方向的位置更新: x = x0 + vx * t
  3. 游戏设计思路
    • 背景设计
    • 整个游戏设计:地图、玩家

二、代码实现

面向对象写法

将每一个元素都写成一个 class,方便维护,整个游戏为一个 class


创建游戏窗口类

html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>拳皇</title>
    <link rel="stylesheet" href="/KOF/static/css/base.css">
    <script src="https://cdn.acwing.com/static/jquery/js/jquery-3.3.1.min.js"></script>
</head>

<body>
    <div id="kof"></div>

    <script type="module">
        import { KOF } from "/KOF/static/js/base.js";

        let kof = new KOF('kof');
    </script>
</body>

</html>

css

#kof {
    width: 1280px;
    height: 720px;
    background-image: url(/KOF/static/images/background/0.gif);
    background-size: 200% 100%;
    background-position: top;
}

js

class KOF { // 整个游戏类,包含两个类:一个是地图类,另一个是玩家类
    constructor(id) {
        this.$kof = $('#' + id);
    }
}
export {
    KOF
}

实现效果如下

在这里插入图片描述


整个游戏实现

1. 创建 ac_game_object 类

  1. 为什么game_mapplayer 等对象都需要在每秒画 60 60 60 次以达到移动动画的效果,所以我们创建一个共同的基类 ac_game_objectgame_mapplayer 等对象继承 ac_game_object 这个基类即可。

  2. 作用:实现 3 个元素每秒钟都刷新 60

  3. js 代码实现

// ac_game_object -> base.js
let AC_GAME_OBJECTS = [];	// 用于存对象的所有元素(每一帧都需要将这个对象的所有元素刷新一次)

class AcGameObject {
    constructor() {
        AC_GAME_OBJECTS.push(this);	// 存储对象
        this.timedelta = 0; // 当前这帧距离上一帧的时间间隔,每个object对象都需要存储当前一帧与上一帧的时间间隔,每个物体的速度取决于时间间隔
        this.has_call_start = false; // 表示当前对象是否调用过start函数(每个对象的 start 函数只执行一次)
    }

    start() {   // 初始执行一次,用于初始化

    }

    update() {  // 每一帧都会执行一次(第一帧除外,第一帧执行 start 函数)

    }

    destroy() { // 删除对象
        for (let i in AC_GAME_OBJECTS) {
            if (AC_GAME_OBJECTS[i] == this) {
                AC_GAME_OBJECTS.splice(i, i);
                break;
            }
        }
    }
}

let last_timestamp; // 上一帧执行的时刻

let AC_GAME_OBJECTS_FRAME = (timestamp) => { // timestamp 表示当前函数执行的时刻
    for (let obj of AC_GAME_OBJECTS) {
        if (!obj.has_call_start) {	// 如果对象没有执行过start函数
            obj.start();
            obj.has_call_start = true;
        } else {
            obj.timedelta = timestamp - last_timestamp;
            obj.update();
        }
    }
    last_timestamp = timestamp; //更新上次调用函数的时刻
    requestAnimationFrame(AC_GAME_OBJECTS_FRAME);
}

requestAnimationFrame(AC_GAME_OBJECTS_FRAME);

export {
    AcGameObject
}

2. 定义 game_map 对象

// game_map -> base.js
import { AcGameObject } from '/static/js/ac_game_object/base.js';
import { Controller } from "/static/js/controller/base.js"

class GameMap extends AcGameObject {
    constructor(root) {
        super();

        this.root = root;
        this.$canvas = $('<canvas width="1280" height="720" tabindex=0></canvas>'); //jQuery用法,tabindex=0使得可以聚焦读取键盘输入
        this.ctx = this.$canvas[0].getContext('2d'); //取出canvas给ctx,这里参考canvas用法
        this.root.$kof.append(this.$canvas);    // 将canvas加入id为kof的div中
        this.$canvas.focus(); // 为了让canvas获取输入,将canvas聚焦

        this.controller = new Controller(this.$canvas);
    }

    start() {   // 初始执行一次

    }

    update() {  // 每一帧都执行
        this.render();
    }

    render() {  //render 为清空函数,渲染函数中需要将每一帧地图都清空,否则物体运动过程会一直停留在地图上
        // this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
        this.ctx.fillStyle = 'black';
        this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
    }
}

export {
    GameMap
}

3. 定义 player 对象

1. 实现两个玩家

用两个矩形代表两个玩家

// player -> base.js
import { AcGameObject } from "/static/js/ac_game_object/base.js";

export class Player extends AcGameObject {
	// 这里root表示大类KOF,作用是方便去索引整个地图上的每一个元素,大类KOF包含两个小类玩家与地图
    constructor(root, info) {   // info:player的相关属性
        super();

        this.root = root;
        this.id = info.id;
        this.x = info.x;
        this.y = info.y;
        this.width = info.width;
        this.height = info.height;
        this.color = info.color;

        this.direction = 1; // 方向,正方向为 1,负方向为 -1

        this.vx = 0;        // 水平方向速度
        this.vy = 0;        // 竖直方向速度

        this.speedx = 400; // 水平方向初始速度
        this.speedy = 1000; // 竖直方向初始速度

        this.gravity = 50; // 重力加速度
        this.ctx = this.root.game_map.ctx;  //这里引入canvas便于下一步操作
    }

    start() {

    }

    move() {
        this.vy += this.gravity;
        this.x += this.vx * this.timedelta / 1000;
        this.y += this.vy * this.timedelta / 1000;
        if (this.y > 500) {
            this.y = 500;
            this.vy = 0;
        }
    }


    update() {
        this.move();
        this.render();
    }

    render() {
        this.ctx.fillStyle = this.color;
        this.ctx.fillRect(this.x, this.y, this.width, this.height);
    }
}
// 主类 base.js 中创建地图与玩家对象
import { GameMap } from "/static/js/game_map/base.js";
import { Player } from "/static/js/player/base.js"

// 创建一个类KOF表示当前的大窗口,此大类包含玩家对象,地图对象
class KOF {
    constructor(id) {
        this.$kof = $('#' + id);
        //创建地图
        this.game_map = new GameMap(this);
        //创建玩家
        this.players = [
        	// 第一名玩家
            new Player(this, { //player对象需要传入root与info
                id: 0,
                x: 200,
                y: 0,
                width: 120,
                height: 200,
                color: 'blue',
            }),

            // 第二名玩家
            new Player(this, {
                id: 1,
                x: 900,
                y: 0,
                width: 120,
                height: 200,
                color: 'red',
            })
        ];
    }
}
export {
    KOF
}

在这里插入图片描述


4. 定义controller 对象

状态机实现玩家不同状态间的转换
在这里插入图片描述

// controller -> base.js
export class Controller {   // 用于判断当前摁住了哪个键
    constructor($canvas) {
        this.$canvas = $canvas;

        this.pressed_keys = new Set(); //set用于存储当前按住了哪个键,重复的键不会重新加入
        this.start();
    }

    start() {
        let outer = this;  // 这里pressed_keys是Controller对象下的值,不是convas的,所以要使用outer
        this.$canvas.keydown(function (e) {
            outer.pressed_keys.add(e.key); //这里this指的是canvas,outer指的是controller
        });

        this.$canvas.keyup(function (e) {
            outer.pressed_keys.delete(e.key);
        });
    }
}

5. 在 player 对象中添加 update_control 函数

  • 用于实现两名玩家的移动
// player -> base.js
import { AcGameObject } from "/static/js/ac_game_object/base.js";

export class Player extends AcGameObject {
    constructor(root, info) {   // info:player的相关属性
        super();

        this.root = root;
        this.id = info.id;
        this.x = info.x;
        this.y = info.y;
        this.width = info.width;
        this.height = info.height;
        this.color = info.color;

        this.direction = 1; // 方向,正方向为 1,负方向为 -1

        this.vx = 0;        // 水平方向速度
        this.vy = 0;        // 竖直方向速度

        this.speedx = 400; // 水平方向初始速度
        this.speedy = -1000; // 竖直方向初始速度

        this.gravity = 50; // 重力加速度
        this.ctx = this.root.game_map.ctx;
        this.pressed_keys = this.root.game_map.controller.pressed_keys;

        this.status = 3;   // 0:准备(静止),1:向前,2:向后,3:跳跃,4:攻击,5:被打,6:死亡
    }

    start() {

    }

    update_move() {
        this.vy += this.gravity;
        this.x += this.vx * this.timedelta / 1000;
        this.y += this.vy * this.timedelta / 1000;
        if (this.y > 500) {
            this.y = 500;
            this.vy = 0;
            this.status = 0;
        }
    }

    update_control() { //更新按下的键位
        let w, a, d, space;
        if (this.id === 0) { // 第一名玩家
            w = this.pressed_keys.has('w'); // w,a,d,' '    
            a = this.pressed_keys.has('a');
            d = this.pressed_keys.has('d');
            space = this.pressed_keys.has(' ');
        } else { // 第二名玩家
            w = this.pressed_keys.has('ArrowUp'); // 上下左右
            a = this.pressed_keys.has('ArrowLeft');
            d = this.pressed_keys.has('ArrowRight');
            space = this.pressed_keys.has('Enter');
        }

        if (this.status === 0 || this.status === 1) { // 静止和移动状态
            if (w) {// 跳跃状态
                if (d) {// 45°跳
                    this.vx = this.speedx;
                } else if (a) {// 135°跳
                    this.vx = -this.speedx;
                } else {// 垂直跳
                    this.vx = 0;
                }
                this.vy = this.speedy;
                this.status = 3;
            } else if (d) {// 向前移动
                this.vx = this.speedx;
                this.status = 1
            } else if (a) {// 向后移动
                this.vx = -this.speedx;
                this.status = 1;
            } else {// 无移动
                this.vx = 0;
                this.status = 0;
            }

        }
    }

    update() {
        this.update_control(); // 每一帧都判断一下当前摁下的是哪个键
        this.update_move();
        this.render();
    }

    render() {
        this.ctx.fillStyle = this.color;
        this.ctx.fillRect(this.x, this.y, this.width, this.height);
    }
}

在这里插入图片描述

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-06-03 23:55:30  更:2022-06-03 23:57:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 17:04:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码