HTML 2048小游戏

棋盘的定义

let D = 4;//阶数
let N = [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072];

一些变量

let board = $("#board");
let Square = N;
let isUndo = false;//是否撤销中

let data = [];//当前棋盘
let dataList = [];//棋盘备份
let scoreList = [];//分数备份
let undo = $("#undo");//撤销按钮
let auto = $("#auto");//自动移动按钮
let isMoving = false, action;
let time = 50;//自动移动间隔
let backupLimit = 10;//棋盘备份上限

自定义方块名

let isUpdating = false;//是否正在更换方块名

$(".square-group").change(function () {
    let val = $("input[name='square']:checked").val();
    switch (val) {
        case "N":
            //经典版
            Square = N;
            break;
        default:
            Square = N;
    }
    isUpdating = true;
    game.dataView();
});

动态css

/**
 * 获取方块内文字长度
 */
function getLen(str) {
    let len = str.length;
    for (let i = 0; i < len; i++) {
        if ((str.charCodeAt(i) & 0xff00) !== 0) {
            len++;
        }
    }
    return len;
}

/**
 * 动态css
 */
function css() {
    let width = document.body.clientWidth;//容器宽度
    let height = window.innerHeight;//窗口高度
    let bodyWidth = Math.min(width, (height - 55) * 0.7);
    board.css("width", `${bodyWidth}px`);
    board.css("height", `${bodyWidth}px`);
    let M = bodyWidth / 6 / D;//方块边距
    let W = (bodyWidth - M * (D + 1)) / D;//方块宽度
    board.css("borderRadius", `${1.25 * M}px`);
    let cells = $(".cell");
    for (let i = 0; i < cells.length; i++) {
        let len = getLen(cells[i].innerText);
        let br = false;
        if (cells[i].innerHTML.includes('<br>')) {
            br = true;
            len /= 4;
            len = Math.round(len);
            len *= 2;
        }
        cells[i].style.width = W + 'px';
        cells[i].style.height = W + 'px';
        cells[i].style.borderRadius = M / 2 + 'px'
        if (len < 4) {
            //1~3个字符时和3字符大小相等
            cells[i].style.fontSize = W * 0.55 + 'px';
        } else {
            cells[i].style.fontSize = W * 1.65 / len + 'px';
        }
        if (br) {
            cells[i].style.lineHeight = W / 2 + 'px'
        } else {
            cells[i].style.lineHeight = W + 'px'
        }
        cells[i].style.margin = M + 'px 0 0 ' + M + 'px'
    }
}

游戏结束的遮罩文字

/**
 * 游戏结束的遮罩文字
 */
function messageCss() {
    let width = board.width();
    let message = $("#message");
    let x = 0.12;
    message.css("fontSize", `${width * x}px`);
    let h = message.height();
    message.css("marginTop", `${(width - h) / 2}px`);
}

/**
 * 清除游戏结束的遮罩
 */
function clear() {
    $("#message-box").css({"display": "none"});
    $("#message-box p").textContent = "";
}

窗口大小变化时,重新测量

window.onresize = function () {
    css();
    if (game.isGameOver()) {
        messageCss();
    }
}

刷新棋盘

/**
 * 刷新棋盘
 */
function refresh() {
    //遍历棋盘
    let parent = $("#grid")[0];
    parent.innerHTML = "";//先清空
    for (let r = 0; r < D; r++) {
        for (let c = 0; c < D; c++) {
            let div = document.createElement("div");
            div.setAttribute("class", "cell");
            div.setAttribute("id", "n" + r + c);
            parent.appendChild(div);
        }
    }
}

其他方法

/**
 * 获取数组元素的下标
 */
function getArrayIndex(arr, obj) {
    let i = arr.length;
    while (i--) {
        if (arr[i] === obj) {
            return i;
        }
    }
    return -1;
}

撤销

/**
 * 撤销
 */
function Undo() {
    if (dataList.length > 1) {
        isUndo = true;
        if (game.status === 0) {
            game.status = 1;//起死回生
            auto.attr("disabled", false);//自动可用
            clear();
        }
        dataList.pop();
        scoreList.pop();
        if (dataList.length === 1) {
            undo.attr("disabled", true);//撤销不可用
        }
        game.score = scoreList[scoreList.length - 1];
        game.dataView();
    } else {
        //使用快捷键时
        commonUtil.message("撤销次数已用尽!", "warning");
    }
}

undo.on("click", function () {
    Undo();
});

自动移动

/**
 * 停止移动
 */
function stopMove() {
    isMoving = false;
    auto.html("自动移动");
    clearInterval(action);
}

/**
 * 自动移动
 */
auto.on("click", function () {
    if (!isMoving) {
        //开始
        isMoving = true;
        $(this).html("停止移动")
        action = setInterval(function () {
            if (game.canLeft) {
                game.moveLeft();
            } else {
                game.moveRight();
            }
            game.moveUp();
        }, time)
    } else {
        stopMove();//停止
    }
});

保存和导入棋盘(代码略)

游戏结束

function gameOver() {
    stopMove();
    auto.attr("disabled", true);//自动不可用
    $("#message-box").css({"display": "block"});
    $("#message").html("无路可走了!<br>试试撤销?");
    messageCss();
}

function youWin() {
    stopMove();
    auto.attr("disabled", true);//自动不可用
    $("#message-box").css({"display": "block"});
    $("#message").html("你赢了!");
    messageCss();
}

游戏环节(核心代码)

/**
 * 游戏环节
 */
const game = {
    score: 0,//开始时分数为0
    gameOver: 0,//游戏结束时游戏状态为0
    status: 1,//个人状态与游戏状态相对应,默认为1
    isExistsBlank: true,
    canLeft: true,
    canRight: true,
    canUp: true,
    canDown: true,
    //游戏开始时还原所有
    start: function () {
        refresh();
        dataList.length = 0;
        scoreList.length = 0;
        undo.html("撤销(0)");
        undo.attr("disabled", true);//撤销不可用
        let arr = [];
        for (let i = 0; i < D; i++) {
            arr[i] = new Array(i);
            for (let j = 0; j < D; j++) {
                arr[i][j] = 0;
            }
        }
        data = arr;
        this.score = 0;
        this.status = 1;
        //赋值
        let type = $("input[name='type']:checked").val();
        if (type === "4") {
            //铺满
            for (let i = 0; i < D * D; i++) {
                this.randomNum();
            }
        } else {
            for (let i = 0; i < D + 1; i++) {
                this.randomNum();
            }
        }
        //更新视图
        this.dataView();
        stopMove();
        auto.attr("disabled", false);//自动可用
        clear();
    },
    //载入游戏
    load: function (arr, score) {
        refresh();
        dataList.length = 0;
        scoreList.length = 0;
        undo.html("撤销(0)");
        undo.attr("disabled", true);//撤销不可用
        data = arr;
        this.score = score;
        this.status = 1;
        //更新视图
        this.dataView();
        stopMove();
        auto.attr("disabled", false);//自动可用
        clear();
    },
    //随机赋值
    randomNum: function () {
        let type = $("input[name='type']:checked").val();
        if (type === "4") {
            //布满全局
            for (let r = 0; r < D; r++) {
                for (let c = 0; c < D; c++) {
                    if (data[r][c] === 0) {
                        data[r][c] = 2;//禁止随机
                    }
                }
            }
            this.isExistsBlank = false;
        } else {
            //循环获取是否方块存在空白位置
            while (true) {
                //获取随机值
                const r = Math.floor(Math.random() * D);//随机生成一个行
                const c = Math.floor(Math.random() * D);//随机生成一个列
                //判断
                if (data[r][c] === 0) {
                    switch (type) {
                        case "1":
                            //经典模式,随机生成2或者4
                            data[r][c] = Math.random() > 0.2 ? 2 : 4;
                            break;
                        case "2":
                            //只生成2
                            data[r][c] = 2;
                            break;
                        case "3":
                            //只生成棋盘中最小的方块
                            let min = Infinity;
                            for (let i = 0; i < data.length; i++) {
                                for (let j = 0; j < data[i].length; j++) {
                                    if (data[i][j] !== 0 && data[i][j] < min) {
                                        min = data[i][j];
                                    }
                                }
                            }
                            if (min === Infinity) {
                                data[r][c] = 2;
                            } else {
                                data[r][c] = min;
                            }
                            break;
                        default:
                            //经典模式,随机生成2或者4
                            data[r][c] = Math.random() > 0.2 ? 2 : 4;
                    }
                    break;
                }
            }
        }
    },
    //更新视图的方法
    dataView: function () {
        let temp;
        if (isUndo) {
            temp = dataList[dataList.length - 1];
        } else {
            temp = data;
        }
        //直接大循环
        for (let r = 0; r < D; r++) {
            //循环行
            for (let c = 0; c < D; c++) {
                //循环里面的每个单元格
                //找到对应的id的div
                const div = $("#n" + r + c)[0];//字符串拼接
                if (temp[r][c] !== 0) {
                    div.innerHTML = Square[getArrayIndex(N, temp[r][c])];//自定义文字展示到div中
                    div.className = "cell n" + temp[r][c];//设置对应div的样式
                } else {
                    div.innerHTML = "";//等于0的时候,div里面的内容直接置空
                    div.className = "cell";
                }
            }
        }
        if (isUpdating) {
            //正在更换方块名
            isUpdating = false;
            css();
            return;
        }
        //更新分数
        $("#score")[0].innerHTML = this.score;
        //判断游戏是否结束
        if (!isUndo) {
            if (this.status === this.gameOver) {
                gameOver();
            }
            let type = $("input[name='type']:checked").val()
            //游戏胜利的判断
            let boardMax = 0;
            for (let i = 0; i < data.length; i++) {
                for (let j = 0; j < data[i].length; j++) {
                    if (data[i][j] !== 0 && data[i][j] > boardMax) {
                        boardMax = data[i][j];
                    }
                }
            }
            switch (type) {
                case "1":
                    //经典模式,合成数达到2^(N^2+1)就胜利
                    if (boardMax >= Math.pow(2, D * D + 1)) {
                        this.status = this.gameOver;
                        youWin();
                    }
                    break;
                case "2":
                case "4":
                    //“只出2”模式,合成数达到2^(N^2)就胜利
                    if (boardMax >= Math.pow(2, D * D)) {
                        this.status = this.gameOver;
                        youWin();
                    }
                    break;
                case "3":
                    //“只出最小”模式,只有合成数达到上限才会赢
                    if (boardMax >= N[N.length - 1]) {
                        this.status = this.gameOver;
                        youWin();
                    }
                    break;
            }
            if (dataList.length > backupLimit) {
                dataList.shift();
            }
            if (scoreList.length > backupLimit) {
                scoreList.shift();
            }
            dataList.push(JSON.parse(JSON.stringify(data)));//记录棋盘
            scoreList.push(this.score);//记录分数
        } else {
            //撤销中
            data = JSON.parse(JSON.stringify(temp));//重要!再次深度拷贝
            this.test1();
            this.test2();
            this.test3();
            isUndo = false;
        }
        undo.html("撤销(" + (dataList.length - 1) + ")");
        if (dataList.length > 1) {
            undo.attr("disabled", false);//撤销可用
        }
        css();
    },
    //判断游戏是否结束的方法
    isGameOver: function () {
        //注:原代码三种情况同时判断,这里区分开
        this.test1();
        this.test2();
        this.test3();
        return !this.isExistsBlank && !this.canLeft && !this.canRight && !this.canUp && !this.canDown;//上面情况全都不符合,表示游戏已经GG了,返回一个true
    },
    test1: function () {
        //是否存在空白
        for (let r = 0; r < D; r++) {
            for (let c = 0; c < D; c++) {
                if (data[r][c] === 0) {
                    this.isExistsBlank = true;
                    return;
                }
            }
        }
        this.isExistsBlank = false;
    },
    test2: function () {
        //能否左右移动
        if (!this.isExistsBlank) {
            for (let r = 0; r < D; r++) {
                for (let c = 0; c < D; c++) {
                    if (c < D - 1) {
                        //判断左右是否有相同,只需要判断到第n-1个格子即可
                        if (data[r][c] === data[r][c + 1]) {
                            this.canLeft = true;
                            this.canRight = true;
                            return;
                        }
                    }
                }
            }
        } else {
            this.canLeft = false;
            this.canRight = false;
            for (let r = 0; r < D; r++) {
                this.test(data[r], "row");
            }
            return;
        }
        this.canLeft = false;
        this.canRight = false;
    },
    test3: function () {
        //能否上下移动
        if (!this.isExistsBlank) {
            for (let r = 0; r < D; r++) {
                for (let c = 0; c < D; c++) {
                    if (r < D - 1) {
                        //判断上下是否有相同,只需要判断到第n-1个格子即可
                        if (data[r][c] === data[r + 1][c]) {
                            this.canUp = true;
                            this.canDown = true;
                            return;
                        }
                    }
                }
            }
        } else {
            this.canUp = false;
            this.canDown = false;
            const getColumns = (arr, i) => arr.map(row => row[i]);
            for (let r = 0; r < D; r++) {
                this.test(getColumns(data, r), "col");
            }
            return;
        }
        this.canUp = false;
        this.canDown = false;
    },
    test: function (a, type) {
        //数组的判断,适用于未填满的棋盘
        let len = a.length;
        let start = a.indexOf(0);
        let end = a.lastIndexOf(0);
        let count = 0;
        //先判断是否有相邻的相同方块
        if (type === "row") {
            for (let i = 0; i < len; i++) {
                if (a[i] === 0) {
                    count++;
                }
                if (i < len - 1) {
                    //判断左右是否有相同,只需要判断到第n-1个格子即可
                    if (a[i] !== 0 && a[i] === a[i + 1]) {
                        this.canLeft = true;
                        this.canRight = true;
                        return;
                    }
                }
            }
            if (count === len) {
                return;
            }
            if (start === -1 && end === -1) {
                return;
            } else if (start > 0 && end === len - 1 && count === end - start + 1) {
                this.canRight = true;
                return;
            } else if (start === 0 && end < len - 1 && count === end - start + 1) {
                this.canLeft = true;
                return;
            } else {
                this.canLeft = true;
                this.canRight = true;
                return;
            }
        }
        if (type === "col") {
            for (let i = 0; i < len; i++) {
                if (a[i] === 0) {
                    count++;
                }
                if (i < len - 1) {
                    //判断上下是否有相同,只需要判断到第n-1个格子即可
                    if (a[i] !== 0 && a[i] === a[i + 1]) {
                        this.canUp = true;
                        this.canDown = true;
                        return;
                    }
                }
            }
            if (count === len) {
                return;
            }
            if (start === -1 && end === -1) {
            } else if (start > 0 && end === len - 1 && count === end - start + 1) {
                this.canDown = true;
            } else if (start === 0 && end < len - 1 && count === end - start + 1) {
                this.canUp = true;
            } else {
                this.canUp = true;
                this.canDown = true;
            }
        }
    },
    //移动的方法
    //数字左移
    moveLeft: function () {
        //移动之前转化一次字符串
        const before = String(data);
        //循环每行数据
        for (let r = 0; r < D; r++) {
            //处理每一行的函数
            this.moveLeftInRow(r);
        }
        //移动之后转换一次
        const after = String(data);
        //判断
        if (before !== after) {
            //生成方块
            this.randomNum();
            if (this.isGameOver()) {
                //如果游戏结束
                this.status = this.gameOver;//自己状态等于游戏结束状态
            }
            //更新视图
            this.dataView();
        }
    },
    //处理每一行的数据
    moveLeftInRow: function (r) {
        //循环获取后面的数据,最左边不用考虑
        for (let c = 0; c < D - 1; c++) {
            //变量接收
            const nextC = this.moveLeftNum(r, c);
            //判断是否为-1,否则则为找到数字
            if (nextC !== -1) {
                if (data[r][c] === 0) {
                    //如果当前的数等于0,则当前的数和找到的数进行比较
                    data[r][c] = data[r][nextC];
                    //找到的数清空变为0
                    data[r][nextC] = 0;
                    //再次从最左边的数进行循环
                    c--;
                } else if (data[r][c] === data[r][nextC]) {
                    //如果当前的数等于找到的数,则相加
                    data[r][c] *= 2;
                    //找到的数清空变为0
                    data[r][nextC] = 0;
                    //合成的数增加到得分
                    this.score += data[r][c];
                }
            } else {
                //如果没有找到数,则退出循环
                break;
            }
        }
    },
    moveLeftNum: function (r, c) {
        //左移
        //循环获取后面的数据,最左边不用考虑
        for (let i = c + 1; i < D; i++) {
            //判断后面是否找到数字
            if (data[r][i] !== 0) {
                //返回下标
                return i;
            }
        }
        //如果没有找到,返回
        return -1;
    },
    //移动的方法
    //数字右移
    moveRight: function () {
        //移动之前转化一次字符串
        const before = String(data);
        //循环每行数据
        for (let r = 0; r < D; r++) {
            //处理每一行的函数
            this.moveRightInRow(r);
        }
        //移动之后转换一次
        const after = String(data);
        //判断
        if (before !== after) {
            //生成方块
            this.randomNum();
            if (this.isGameOver()) {
                //如果游戏结束
                this.status = this.gameOver;//自己状态等于游戏结束状态
            }
            //更新视图
            this.dataView();
        }
    },
    //处理每一行的数据
    moveRightInRow: function (r) {
        //循环获取前面的数据,最左边不用考虑
        for (let c = D - 1; c >= 0; c--) {
            //变量接收
            const nextC = this.moveRightNum(r, c);
            //判断是否为-1,否则则为找到数字
            if (nextC !== -1) {
                if (data[r][c] === 0) {
                    //如果当前的数等于0,则当前的数和找到的数进行比较
                    data[r][c] = data[r][nextC];
                    //找到的数清空变为0
                    data[r][nextC] = 0;
                    //再次从最右边的数进行循环
                    c++;
                } else if (data[r][c] === data[r][nextC]) {
                    //如果当前的数等于找到的数,则相加
                    data[r][c] *= 2;
                    //找到的数清空变为0
                    data[r][nextC] = 0;
                    //合成的数增加到得分
                    this.score += data[r][c];
                }
            } else {
                //如果没有找到数,则退出循环
                break;
            }
        }
    },
    moveRightNum: function (r, c) {
        //右移
        //循环获取前面的数据,最右边不用考虑
        for (let i = c - 1; i >= 0; i--) {
            //判断前面是否找到数字
            if (data[r][i] !== 0) {
                //返回下标
                return i;
            }
        }
        //如果没有找到,返回
        return -1;
    },
    //移动的方法
    //数字上移
    moveUp: function () {
        //移动之前转化一次字符串
        const before = String(data);
        //循环每行数据
        for (let c = 0; c < D; c++) {
            //处理每一行的函数
            this.moveUpInRow(c);
        }
        //移动之后转换一次
        const after = String(data);
        //判断
        if (before !== after) {
            //生成方块
            this.randomNum();
            if (this.isGameOver()) {
                //如果游戏结束
                this.status = this.gameOver;//自己状态等于游戏结束状态
            }
            //更新视图
            this.dataView();
        }
    },
    //处理每一行的数据
    moveUpInRow: function (c) {
        //循环获取前面的数据,最上面不用考虑
        for (let r = 0; r < D - 1; r++) {
            //变量接收
            const nextR = this.moveUpNum(r, c);
            //判断是否为-1,否则则为找到数字
            if (nextR !== -1) {
                if (data[r][c] === 0) {
                    //如果当前的数等于0,则当前的数和找到的数进行比较
                    data[r][c] = data[nextR][c];
                    //找到的数清空变为0
                    data[nextR][c] = 0;
                    //再次从最上面的数进行循环
                    r--;
                } else if (data[r][c] === data[nextR][c]) {
                    //如果当前的数等于找到的数,则相加
                    data[r][c] *= 2;
                    //找到的数清空变为0
                    data[nextR][c] = 0;
                    //合成的数增加到得分
                    this.score += data[r][c];
                }
            } else {
                //如果没有找到数,则退出循环
                break;
            }
        }
    },
    moveUpNum: function (r, c) {
        //上移
        //循环获取上面的数据,最右边不用考虑
        for (let i = r + 1; i < D; i++) {
            //判断下面是否找到数字
            if (data[i][c] !== 0) {
                //返回下标
                return i;
            }
        }
        //如果没有找到,返回
        return -1;
    },
    //移动的方法
    //数字下移
    moveDown: function () {
        //移动之前转化一次字符串
        const before = String(data);
        //循环每行数据
        for (let c = 0; c < D; c++) {
            //处理每一行的函数
            this.moveDownInRow(c);
        }
        //移动之后转换一次
        const after = String(data);
        //判断
        if (before !== after) {
            //生成方块
            this.randomNum();
            if (this.isGameOver()) {
                //如果游戏结束
                this.status = this.gameOver;//自己状态等于游戏结束状态
            }
            //更新视图
            this.dataView();
        }
    },
    //处理每一行的数据
    moveDownInRow: function (c) {
        //循环获取前面的数据,最下面不用考虑
        for (let r = D - 1; r >= 0; r--) {
            //变量接收
            const nextR = this.moveDownNum(r, c);
            //判断是否为-1,否则则为找到数字
            if (nextR !== -1) {
                if (data[r][c] === 0) {
                    //如果当前的数等于0,则当前的数和找到的数进行比较
                    data[r][c] = data[nextR][c];
                    //找到的数清空变为0
                    data[nextR][c] = 0;
                    //再次从最下面的数进行循环
                    r++;
                } else if (data[r][c] === data[nextR][c]) {
                    //如果当前的数等于找到的数,则相加
                    data[r][c] *= 2;
                    //找到的数清空变为0
                    data[nextR][c] = 0;
                    //合成的数增加到得分
                    this.score += data[r][c];
                }
            } else {
                //如果没有找到数,则退出循环
                break;
            }
        }
    },
    moveDownNum: function (r, c) {
        //下移
        //循环获取前面的数据,最下面不用考虑
        for (let i = r - 1; i >= 0; i--) {
            //判断上面是否找到数字
            if (data[i][c] !== 0) {
                //返回下标
                return i;
            }
        }
        //如果没有找到,返回
        return -1;
    }
};

移动端的滑动处理


/**
 * 根据起点终点返回方向
 * @return 1向上 2向下 3向左 4向右 0未滑动
 */
function getDirection(startX, startY, endX, endY) {
    const X = endX - startX;
    const Y = endY - startY;
    //滑动距离太短
    if (Math.abs(X) < 2 && Math.abs(Y) < 2) {
        return 0;
    }
    if (Y < 0 && Math.abs(Y) > Math.abs(X)) {
        return 1;
    } else if (Y > 0 && Math.abs(Y) > Math.abs(X)) {
        return 2;
    } else if (X < 0 && Math.abs(X) > Math.abs(Y)) {
        return 3;
    } else if (X > 0 && Math.abs(X) > Math.abs(Y)) {
        return 4;
    }
}

let startX, startY;

/**
 * 手指接触屏幕
 */
board[0].addEventListener("touchstart", function (e) {
    e.preventDefault();//防止滚动页面
    startX = e.touches[0].pageX;
    startY = e.touches[0].pageY;
}, {passive: false});//手指离开屏幕

/**
 * 手指离开屏幕
 */
board[0].addEventListener("touchend", function (e) {
    e.preventDefault();//防止滚动页面
    if (game.status !== game.gameOver) {
        let endX, endY;
        endX = e.changedTouches[0].pageX;
        endY = e.changedTouches[0].pageY;
        const direction = getDirection(startX, startY, endX, endY);
        switch (direction) {
            case 1:
                game.moveUp();
                break;
            case 2:
                game.moveDown()
                break;
            case 3:
                game.moveLeft();
                break;
            case 4:
                game.moveRight()
                break;
            default:
                break;
        }
    }
}, {passive: false});

键盘控制

/**
 * 键盘控制
 */
document.addEventListener("keydown", function (e) {
    //撤销:Ctrl+Z
    if (e.ctrlKey && e.key === "z") {
        Undo();
    }
    //上下左右
    if (game.status !== game.gameOver) {
        switch (e.key) {
            case "ArrowUp":
                e.preventDefault();
                game.moveUp();
                break;
            case "ArrowDown":
                e.preventDefault();
                game.moveDown()
                break;
            case "ArrowLeft":
                e.preventDefault();
                game.moveLeft();
                break;
            case "ArrowRight":
                e.preventDefault();
                game.moveRight()
                break;
        }
    }
});

最后,开始游戏!

game.start();//游戏开始
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值