如何用canvas制作一个华容道小游戏(乞丐版)

我大抵是废了φ(..) ,横竖都学不进去,上课知识不进脑子,学习光想划水摸鱼,心中仅剩的良知告诉我这样下去是铁定不行的哇,既然学不进去,何不打把游戏,既然要打游戏,为啥不自己写个小游戏嘞٩(๑>◡<๑)۶?手动狗头。

 虽然我有着强烈的制作意愿,但是当初学的unity3D的知识早就还给老师了,而且就我一个人的话,做大型游戏先不说我一个人干不干的过来,首要面对的问题就是,没这个能力你知道吧。于是我想起来了小时候第一次去科技馆,玩的华容道,碰巧之前学过一点canvas,做的话应该是可以做的,虽然我上次用canvas还是在上次,那么......

 好了,废话不多说,先写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>
    <style>
        *{
            margin: 0 ;
            padding: 0 ;
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="240" height="240"></canvas>
    <script  type="text/javascript" src="./index.js"></script>
</body>
</html>

有一说一,这个html页面是真的简单,毕竟只用了一个canvas标签,也就没啥好说的了对吧,那接下来就上js吧。

我在写html的时候有多轻松,在写js的时候就有多难受。我最初以为写一个华容道是一件很简单的事情,毕竟用canvas画几个方块,然后写上左右移动的函数,写上碰撞检测的函数,写上判断通关的函数,这个游戏也就写完了。但是开始写了才发现,貌似实际情况和我幻想的有那么亿丝丝的不一样,其他几个都好写,就是这个碰撞检测有些难顶。怎么判断对应位置是否有方块?怎么判断墙在何处?要是直接用canvas划线来画方块的话,判断起来当是很困难的,虽然没有细细思考这样做的可行性是多少,但是哪怕能做,也一定是比较复杂的,而我之所以要写这个小游戏,不就是为了放松吗,所以此刻摆在我面前的有两条路,一条是放弃,另一条还是放弃。

当然,放弃是不可能放弃的,因为我想到了一个好办法,那就是用一个数组,来存值,存对应位置是否有方块,以及方块的大小形状都是啥。就好比接下来这个数组。

[
    [['张飞','dir'],['曹操','big'],['曹操','big'],['赵云','dir']],
    [['张飞','dir'],['曹操','big'],['曹操','big'],['赵云','dir']],
    [['马超','dir'],['关羽','bro'],['关羽','bro'],['黄忠','dir']],
    [['马超','dir'],['小兵','squ'],['小兵','squ'],['黄忠','dir']],
    [['小兵','squ'],[null,null],[null,null],['小兵','squ']],
]

在这个数组里,每一个子数组都代表着一行中的四个方格,这个子数组中的每个子数组,第一个属性是当前方格的棋子名称,以及这个棋子的形状是怎么样的,dir是竖长方形,bro是横长方形,squ是只占当前一个格子的小正方形,big是四个格子之大的大正方形。

既然有了记录当前状态的数组,那么就要开始画棋盘和棋子了,我先定义了棋子的构造函数

    function Rect(x, y, width, height, color) {
        this.x = x
        this.y = y
        this.width = width
        this.height = height
        this.color = color
    }
    Rect.prototype.draw = function () {
        ctx.beginPath()
        ctx.fillStyle = this.color
        ctx.fillRect(this.x, this.y, this.width, this.height)//从x,y处填充矩形,宽度为width,高度为height
        ctx.strokeRect(this.x, this.y, this.width, this.height)//从x,y处绘制矩形,宽度为width,高度为height
    }

接下来就是画初始的棋盘了,我设置的每一个格子的宽度高度都是20,想要改变棋子大小的同学们记得将四种构造函数对应的数值一同变动一二。对于四种方块的绘制方法,我的思路是在遍历到第一个值的时候,也就是这个棋子的左上角那个方块的时候,绘制整个棋子,同时将棋子其他位置的值置为0,避免重复绘制。写好了绘制四种方块的方法后,我就用了一个双重for循环遍历数组,绘制整张图。最后则是判断是否闯关成功。

drawCheeks = () =>{
        ctx.beginPath()
        ctx.strokeRect(20,20,80,100)
        ctx.stroke()
        ctx.closePath()
        let temp = JSON.parse(JSON.stringify(cheeks));
        let cheekColor = []
        cheekColor['张飞'] = 'black';
        cheekColor['赵云'] = 'brown';
        cheekColor['马超'] = 'silver';
        cheekColor['关羽'] = 'red';
        cheekColor['黄忠'] = 'yellow';
        cheekColor['曹操'] = 'blue';
        cheekColor['小兵'] = 'green';
        function square(i,j,color){
            var cheek = new Rect(20+20*j,20+20*i,20,20,color);
            cheek.draw();
            temp[i][j] = 0;
        }
        function Bigsquare(i,j,color){
            var cheek = new Rect(20+20*j,20+20*i,40,40,color);
            cheek.draw();
            temp[i][j] = 0;
            temp[i+1][j] = 0;
            temp[i][j+1] = 0;
            temp[i+1][j+1] = 0;
        }
        function dirOblang(i,j,color){
            var cheek = new Rect(20+20*j,20+20*i,20,40,color);
            cheek.draw();
            temp[i][j] = 0;
            temp[i+1][j] = 0;
        }
        function broOblang(i,j,color){
            var cheek = new Rect(20+20*j,20+20*i,40,20,color);
            cheek.draw();
            temp[i][j] = 0;
            temp[i][j+1] = 0;
        }
        function drawSqare(tag,i,j,color){
            if(tag == 'squ'){
                return square(i,j,color);
            }else if(tag == 'big'){
                return Bigsquare(i,j,color);
            }else if(tag == 'dir'){
                return dirOblang(i,j,color);
            }else if(tag == 'bro'){
                return broOblang(i,j,color);
            }
        }
        for(let i=0;i<temp.length;i++){
            for(let j=0;j<temp[0].length;j++){
                if(temp[i][j] === null){
                    continue;
                }else{
                    drawSqare(temp[i][j][1],i,j,cheekColor[temp[i][j][0]])
                }
            }
        }
        if(temp[3][2][0] == "曹操"){
            const con = confirm(`闯关成功,本次共走了${this.grade}步,要进入下一关吗`)
            if (con) {
                custom++;
                cheeks = customs[custom];
                drawCheeks();
            }
            return
        }
    }
    drawCheeks();

棋盘绘制成功后如图所示,emmm,有点简陋,但是无妨,只是没加皮肤罢了,以后有机会一定会加上的_(:3」∠)_。

 那接下来就要写点击的函数了,这块也不难,就是根据点击事件来判断点击的区域是否位于棋盘内,位于棋盘内的话则判断选中哪个棋子,相信大家都能看明白,也就不做过多的解释了。

document.addEventListener("click",function(e){
        let j = Math.floor((e.pageX-20)/20);
        let i = Math.floor((e.pageY-20)/20);
        if(i<5 && j<4){
            clickIt(i,j)
        }
    })
    clickIt = function(i,j){
        if(cheeks[i][j]){
            let cheekVal = cheeks[i][j][0];
            if(cheeks[i][j][1] == 'dir'){
                if(i>0 && cheeks[i-1][j][0]==cheekVal){
                    now(i-1,j,cheekVal,cheeks[i][j][1]);
                }else{
                    now(i,j,cheekVal,cheeks[i][j][1]);
                }
            }else if(cheeks[i][j][1] == 'bro'){
                if(j>0 && cheeks[i][j-1][0]==cheekVal){
                    now(i,j-1,cheekVal,cheeks[i][j][1]);
                }else{
                    now(i,j,cheekVal,cheeks[i][j][1]);
                }
            }else if(cheeks[i][j][1] == 'big'){
                if(i>0 && cheeks[i-1][j][0]==cheekVal){
                    if(j>0 && cheeks[i][j-1][0]==cheekVal){
                        now(i-1,j-1,cheekVal,cheeks[i][j][1]);
                    }else{
                        now(i-1,j,cheekVal,cheeks[i][j][1]);
                    }
                }else{
                    if(j>0 && cheeks[i][j-1][0]==cheekVal){
                        now(i,j-1,cheekVal,cheeks[i][j][1]);
                    }else{
                        now(i,j,cheekVal,cheeks[i][j][1]);
                    }
                }
            }else{
                now(i,j,cheekVal,cheeks[i][j][1]);
            }
        }
    }
    now = function(i,j,cheekVal,tag){
        x = j;
        y = i;
        val = cheekVal;
        cheekTag = tag;
    }

接下来就是监听键盘了,准确来说是监听上下左右四个按键,好根据当前选中的方块和按的是哪个按键来做出相应的动作。

    document.onkeydown = function (e) {
        e = e || window.event
        // 左37  上38  右39  下40
        switch (e.keyCode) {
            case 37:
                toLeft();
                break
            case 38:
                toUp();
                break 
            case 39:
                toRight();
                break
            case 40:
                toDown();
                break
        }
    }

监听完键盘事件,就要写执行对应动作的函数了,这里四个函数大体上是相同的,我就以向左移动的函数为例说说吧。这块代码我写的其实不好,毕竟使用了过多ifelse,如果以后去工作了的话大概率会被测试同学打,但是谁叫我现在还在上学嘞(灬°ω°灬),本来其实是想要多写几个函数优化一下代码结构的,但是吧,不想写了。。。。

这串代码是根据选中位置,因为前面处理点击的时候已经自动将点击位置转换为点击的棋子的左上角了,因此这里只需要判断当前棋子是否是最左侧那一列的棋子,是的话无法移动,否则判断该棋子若左移的话是否会碰到其他棋子,会的话则无法移动。要是可以移动的话,就对储存棋盘状态的数组进行处理,然后重新执行绘制函数。

    toLeft = () =>{
        if(x!=0){
            tag = cheekTag;
            if(tag == 'bro'){
                if(cheeks[y][x-1][0] === null){
                    cheeks[y][x+1] = [null,null];
                    cheeks[y][x-1] = [val,tag];
                }
            }else if(tag == 'dir'){
                if(cheeks[y][x-1][0] === null && cheeks[y+1][x-1][0] === null){
                    cheeks[y][x-1] = [val,tag];
                    cheeks[y+1][x-1] = [val,tag];
                    cheeks[y][x] = [null,null];
                    cheeks[y+1][x] = [null,null];
                }
            }else if(tag == 'big'){
                if(cheeks[y][x-1][0] === null && cheeks[y+1][x-1][0] === null){
                    cheeks[y][x-1] = [val,tag];
                    cheeks[y+1][x-1] = [val,tag];
                    cheeks[y][x+1] = [null,null];
                    cheeks[y+1][x+1] = [null,null];
                }
            }else if(tag == 'squ'){
                if(cheeks[y][x-1][0] === null){
                    cheeks[y][x-1] = [val,tag];
                    cheeks[y][x] = [null,null];
                }
            }
            console.log(cheeks)
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            grade++;
            drawCheeks();
        }
    }

js的全部代码如下,目前只在关卡的数组里写了三关,即便如此我目前还是一关也没有通过......

let x,y,val,cheekTag,grade=0,custom = 0;
play()
function play() {
    const canvas = document.getElementById('canvas')
    const ctx = canvas.getContext('2d')
    let customs = [
        [
            [['张飞','dir'],['曹操','big'],['曹操','big'],['小兵','squ']],
            [['张飞','dir'],['曹操','big'],['曹操','big'],['小兵','squ']],
            [['马超','dir'],['赵云','dir'],['黄忠','dir'],['小兵','squ']],
            [['马超','dir'],['赵云','dir'],['黄忠','dir'],['小兵','squ']],
            [[null,null],['关羽','bro'],['关羽','bro'],[null,null]],
        ],
        [
            [['赵云','dir'],['曹操','big'],['曹操','big'],['小兵','squ']],
            [['赵云','dir'],['曹操','big'],['曹操','big'],['小兵','squ']],
            [['关羽','bro'],['关羽','bro'],['小兵','squ'],['小兵','squ']],
            [['马超','dir'],['张飞','bro'],['张飞','bro'],['黄忠','dir']],
            [['马超','dir'],[null,null],[null,null],['黄忠','dir']],
        ],
        [
            [['张飞','dir'],['曹操','big'],['曹操','big'],['赵云','dir']],
            [['张飞','dir'],['曹操','big'],['曹操','big'],['赵云','dir']],
            [['马超','dir'],['关羽','bro'],['关羽','bro'],['黄忠','dir']],
            [['马超','dir'],['小兵','squ'],['小兵','squ'],['黄忠','dir']],
            [['小兵','squ'],[null,null],[null,null],['小兵','squ']],
        ]
    ]
    let cheeks = customs[custom];
    function Rect(x, y, width, height, color) {
        this.x = x
        this.y = y
        this.width = width
        this.height = height
        this.color = color
    }
    Rect.prototype.draw = function () {
        ctx.beginPath()
        ctx.fillStyle = this.color
        ctx.fillRect(this.x, this.y, this.width, this.height)//从x,y处填充矩形,宽度为width,高度为height
        ctx.strokeRect(this.x, this.y, this.width, this.height)//从x,y处绘制矩形,宽度为width,高度为height
    }
    x=0,y=0,val=1;//默认选中左上角的方块
    drawCheeks = () =>{
        ctx.beginPath()
        ctx.strokeRect(20,20,80,100)
        ctx.stroke()
        ctx.closePath()
        let temp = JSON.parse(JSON.stringify(cheeks));
        let cheekColor = []
        cheekColor['张飞'] = 'black';
        cheekColor['赵云'] = 'brown';
        cheekColor['马超'] = 'silver';
        cheekColor['关羽'] = 'red';
        cheekColor['黄忠'] = 'yellow';
        cheekColor['曹操'] = 'blue';
        cheekColor['小兵'] = 'green';
        function square(i,j,color){
            var cheek = new Rect(20+20*j,20+20*i,20,20,color);
            cheek.draw();
            temp[i][j] = 0;
        }
        function Bigsquare(i,j,color){
            var cheek = new Rect(20+20*j,20+20*i,40,40,color);
            cheek.draw();
            temp[i][j] = 0;
            temp[i+1][j] = 0;
            temp[i][j+1] = 0;
            temp[i+1][j+1] = 0;
        }
        function dirOblang(i,j,color){
            var cheek = new Rect(20+20*j,20+20*i,20,40,color);
            cheek.draw();
            temp[i][j] = 0;
            temp[i+1][j] = 0;
        }
        function broOblang(i,j,color){
            var cheek = new Rect(20+20*j,20+20*i,40,20,color);
            cheek.draw();
            temp[i][j] = 0;
            temp[i][j+1] = 0;
        }
        function drawSqare(tag,i,j,color){
            if(tag == 'squ'){
                return square(i,j,color);
            }else if(tag == 'big'){
                return Bigsquare(i,j,color);
            }else if(tag == 'dir'){
                return dirOblang(i,j,color);
            }else if(tag == 'bro'){
                return broOblang(i,j,color);
            }
        }
        for(let i=0;i<temp.length;i++){
            for(let j=0;j<temp[0].length;j++){
                if(temp[i][j] === null){
                    continue;
                }else{
                    drawSqare(temp[i][j][1],i,j,cheekColor[temp[i][j][0]])
                }
            }
        }
        if(temp[3][2][0] == "曹操"){
            const con = confirm(`闯关成功,本次共走了${this.grade}步,要进入下一关吗`)
            if (con) {
                custom++;
                cheeks = customs[custom];
                drawCheeks();
            }
            return
        }
    }
    drawCheeks();
    document.addEventListener("click",function(e){
        let j = Math.floor((e.pageX-20)/20);
        let i = Math.floor((e.pageY-20)/20);
        if(i<5 && j<4){
            clickIt(i,j)
        }
    })
    clickIt = function(i,j){
        if(cheeks[i][j]){
            let cheekVal = cheeks[i][j][0];
            if(cheeks[i][j][1] == 'dir'){
                if(i>0 && cheeks[i-1][j][0]==cheekVal){
                    now(i-1,j,cheekVal,cheeks[i][j][1]);
                }else{
                    now(i,j,cheekVal,cheeks[i][j][1]);
                }
            }else if(cheeks[i][j][1] == 'bro'){
                if(j>0 && cheeks[i][j-1][0]==cheekVal){
                    now(i,j-1,cheekVal,cheeks[i][j][1]);
                }else{
                    now(i,j,cheekVal,cheeks[i][j][1]);
                }
            }else if(cheeks[i][j][1] == 'big'){
                if(i>0 && cheeks[i-1][j][0]==cheekVal){
                    if(j>0 && cheeks[i][j-1][0]==cheekVal){
                        now(i-1,j-1,cheekVal,cheeks[i][j][1]);
                    }else{
                        now(i-1,j,cheekVal,cheeks[i][j][1]);
                    }
                }else{
                    if(j>0 && cheeks[i][j-1][0]==cheekVal){
                        now(i,j-1,cheekVal,cheeks[i][j][1]);
                    }else{
                        now(i,j,cheekVal,cheeks[i][j][1]);
                    }
                }
            }else{
                now(i,j,cheekVal,cheeks[i][j][1]);
            }
        }
    }
    now = function(i,j,cheekVal,tag){
        x = j;
        y = i;
        val = cheekVal;
        cheekTag = tag;
    }
    document.onkeydown = function (e) {
        e = e || window.event
        // 左37  上38  右39  下40
        switch (e.keyCode) {
            case 37:
                toLeft();
                break
            case 38:
                toUp();
                break 
            case 39:
                toRight();
                break
            case 40:
                toDown();
                break
        }
    }
    toLeft = () =>{
        if(x!=0){
            tag = cheekTag;
            if(tag == 'bro'){
                if(cheeks[y][x-1][0] === null){
                    cheeks[y][x+1] = [null,null];
                    cheeks[y][x-1] = [val,tag];
                }
            }else if(tag == 'dir'){
                if(cheeks[y][x-1][0] === null && cheeks[y+1][x-1][0] === null){
                    cheeks[y][x-1] = [val,tag];
                    cheeks[y+1][x-1] = [val,tag];
                    cheeks[y][x] = [null,null];
                    cheeks[y+1][x] = [null,null];
                }
            }else if(tag == 'big'){
                if(cheeks[y][x-1][0] === null && cheeks[y+1][x-1][0] === null){
                    cheeks[y][x-1] = [val,tag];
                    cheeks[y+1][x-1] = [val,tag];
                    cheeks[y][x+1] = [null,null];
                    cheeks[y+1][x+1] = [null,null];
                }
            }else if(tag == 'squ'){
                if(cheeks[y][x-1][0] === null){
                    cheeks[y][x-1] = [val,tag];
                    cheeks[y][x] = [null,null];
                }
            }
            console.log(cheeks)
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            grade++;
            drawCheeks();
        }
    }
    toRight = () =>{
        if(x!=3){
            tag = cheekTag;
            if(tag == 'bro' && x <2){
                if(cheeks[y][x+2][0] === null){
                    cheeks[y][x] = [null,null];
                    cheeks[y][x+2] = [val,tag];
                }
            }else if(tag == 'dir'){
                if(cheeks[y][x+1][0] === null && cheeks[y+1][x+1][0] === null){
                    cheeks[y][x+1] = [val,tag];
                    cheeks[y+1][x+1] = [val,tag];
                    cheeks[y][x] = [null,null];
                    cheeks[y+1][x] = [null,null];
                }
            }else if(tag == 'big' && x <2){
                if(cheeks[y][x+2][0] === null && cheeks[y+1][x+2][0] === null){
                    cheeks[y][x+2] = [val,tag];
                    cheeks[y+1][x+2] = [val,tag];
                    cheeks[y][x] = [null,null];
                    cheeks[y+1][x] = [null,null];
                }
            }else{
                if(cheeks[y][x+1][0] === null){
                    cheeks[y][x+1] = [val,tag];
                    cheeks[y][x] = [null,null];
                }
            }
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            grade++;
            drawCheeks();
        }
    }
    toUp = () =>{
        if(y!=0){
            tag = cheekTag;
            if(tag == 'dir'){
                if(cheeks[y-1][x][0] === null){
                    cheeks[y+1][x] = [null,null];
                    cheeks[y-1][x] = [val,tag];
                }
            }else if(tag == 'bro'){
                if(cheeks[y-1][x][0] === null && cheeks[y-1][x+1][0] === null){
                    cheeks[y-1][x] = [val,tag];
                    cheeks[y-1][x+1] = [val,tag];
                    cheeks[y][x] = [null,null];
                    cheeks[y][x+1] = [null,null];
                }
            }else if(tag == 'big'){
                if(cheeks[y-1][x][0] === null && cheeks[y-1][x+1][0] === null){
                    cheeks[y-1][x] = [val,tag];
                    cheeks[y-1][x+1] = [val,tag];
                    cheeks[y+1][x] = [null,null];
                    cheeks[y+1][x+1] = [null,null];
                }
            }else{
                if(cheeks[y-1][x][0] === null){
                    cheeks[y-1][x] = [val,tag];
                    cheeks[y][x] = [null,null];
                }
            }
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            grade++;
            drawCheeks();
        }
    }
    toDown = () =>{
        if(y!=4){
            tag = cheekTag;
            if(tag == 'dir'){
                if(y<3 && cheeks[y+2][x][0] === null){
                    cheeks[y][x] = [null,null];
                    cheeks[y+2][x] = [val,tag];
                }
            }else if(tag == 'bro'){
                if(cheeks[y+1][x][0] === null && cheeks[y+1][x+1][0] === null){
                    cheeks[y+1][x] = [val,tag];
                    cheeks[y+1][x+1] = [val,tag];
                    cheeks[y][x] = [null,null];
                    cheeks[y][x+1] = [null,null];
                }
            }else if(y<3 && tag == 'big'){
                if(cheeks[y+2][x][0] === null && cheeks[y+2][x+1][0] === null){
                    cheeks[y+2][x] = [val,tag];
                    cheeks[y+2][x+1] = [val,tag];
                    cheeks[y][x] = [null,null];
                    cheeks[y][x+1] = [null,null];
                }
            }else{
                if(cheeks[y+1][x][0] === null){
                    cheeks[y+1][x] = [val,tag];
                    cheeks[y][x] = [null,null];
                }
            }
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            grade++;
            drawCheeks();
        }
    }
}

做的很简陋,玩的时候每次点击方块,移动方块后都要重新点击,导致游戏体验很差。虽说知道要如何去改进,但是现在又突然间有了学习的动力,改进这事,以后有机会再说吧。

结果视频:

1679730629453

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HTML5 Video(视频)

HTML5 Video(视频) 在本节内容中&#xff0c;你将了解到在HTML5中视频是如何工作的、主流浏览器支持的视频格式以及如何对网页中的视频进行控制。 很多站点都会使用到视频. HTML5 提供了展示视频的标准。 检测您的浏览器是否支持 HTML5 视频&#xff1a; Web站点上的视频 直…

SeNet论文解读/总结

此文章为深度学习在计算机视觉领域的图片分类经典论文SeNet&#xff08;Squeeze-and-Excitation Networks&#xff09;论文总结。 此系列文章是非常适合深度学习领域的小白观看的图像分类经典论文。系列文章如下&#xff1a; AlexNet&#xff1a;AlexNet论文解读/总结_alexnet…

在CentOS上安装Docker引擎

1,先决条件#### 1-1操作系统要求1-2 卸载旧版本 2,安装方法2-1使用存储库安装设置存储库安装 Docker 引擎 本文永久更新地址: 官方地址&#xff1a;https://docs.docker.com/engine/install/centos/ 1,先决条件 #### 1-1操作系统要求 要安装 Docker Engine&#xff0c;您需要…

【基础算法】链表相关题目

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招算法的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于代码随想录进行的&#xff0c;每个算法代码参考leetcode高赞回答和…

官宣|Apache Flink 1.17 发布公告

Apache Flink PMC&#xff08;项目管理委员&#xff09;很高兴地宣布发布 Apache Flink 1.17.0。Apache Flink 是领先的流处理标准&#xff0c;流批统一的数据处理概念在越来越多的公司中得到认可。得益于我们出色的社区和优秀的贡献者&#xff0c;Apache Flink 在 Apache 社区…

STM32F407控制微型推拉式电磁铁(通过继电器)

1、继电器 继电器相当于开关&#xff0c;单片机通过io口高低电平的控制来控制继电器的开闭。采用继电器的好处除了能够用低电压控制高电压&#xff08;如32单片机控制220V的电压&#xff09;外&#xff0c;还可以防止电流反冲&#xff0c;弄烧单片机。 本文采用3.3v的电磁铁&am…

三、MyBatis核心配置文件详解

核心配置文件中的标签必须按照固定的顺序(有的标签可以不写&#xff0c;但顺序一定不能乱)&#xff1a; properties、settings、typeAliases、typeHandlers、objectFactory、objectWrapperFactory、reflectorFactory、plugins、environments、databaseIdProvider、mappers 一、…

b01lers(php.galf)

目录 前文 正文 前文 <?phpclass A{public $codeNULL;public $argsNULL;public function __construct($code,$argsNULL){$this->code$code;$this->args$args;print_r("2333") ;} public function __invoke($code,$args){echo $code;print_r("执行inv…

记一次若依后台管理系统渗透

前言 最近客户开始hw前的风险排查&#xff0c;让我们帮他做个渗透测试&#xff0c;只给一个单位名称。通过前期的信息收集&#xff0c;发现了这个站点&#xff1a; 没有验证码&#xff0c;再加上这个图标&#xff0c;吸引了我注意&#xff1a; 从弱口令开始 若依默认口令为ad…

Android 12.0 Settings主页面去掉FocusRecyclerView相关功能

1.前言 在12.0的系统rom产品定制化开发中,在系统Settings主页面的主菜单中,在测试某些功能的时候,比如开启护眼模式和改变系统密度会在主菜单第一项的网络菜单头部增加 自定义您的设备和设置护眼模式时间安排 等等相关的设置模块 这对于菜单布局显示相当不美观,所以根据系…

机器学习---降维算法

知其然知其所以然【写在前面】主成分分析&#xff08;PCA&#xff09;原理部分代码部分可视化部分线性判别分析&#xff08;LDA&#xff09;原理部分代码部分可视化部分独立成分分析&#xff08;ICA&#xff09;原理部分代码部分可视化部分t-SNE降维算法原理部分代码部分可视化…

请求响应数据?Controler层注解!

目录1. 请求1.1概述1.2 简单参数1.2.1 原始方式1.2.2 SpringBoot方式1.2.3 参数名不一致1.3 实体参数1.3.1 简单实体对象1.3.2 复杂实体对象1.4 数组集合参数1.4.1 数组1.4.2 集合1.5 日期参数1.6 JSON参数1.7 路径参数2. 响应2.1 ResponseBody2.2 统一响应结果1. 请求 1.1概述…

Hive数据仓库简介

文章目录Hive数据仓库简介一、数据仓库简介1. 什么是数据仓库2. 数据仓库的结构2.1 数据源2.2 数据存储与管理2.3 OLAP服务器2.4 前端工具3. 数据仓库的数据模型3.1 星状模型3.2 雪花模型二、Hive简介1. 什么是Hive2. Hive的发展历程3. Hive的本质4. Hive的优缺点4.1 优点4.2 缺…

Vue2响应式原理

目录 Object.defineProperty() 监听对象中的简单数据类型 监听对象中的对象(可以深层) 监听对象中的数组 借鉴的帖子&#xff1a;Object.defineProperty方法&#xff08;详解&#xff09;_objectdefineproperty_搞前端的小菜的博客-CSDN博客 b站视频讲解&#xff1a;Vue2响…

学习 Python 之 Pygame 开发魂斗罗(十三)

学习 Python 之 Pygame 开发魂斗罗&#xff08;十三&#xff09;继续编写魂斗罗1. 创建敌人2类2. 编写敌人2类的draw()函数3. 编写敌人越界消失函数4. 编写敌人开火函数5. 把敌人2加入地图进行测试继续编写魂斗罗 在上次的博客学习 Python 之 Pygame 开发魂斗罗&#xff08;十…

Adapter基础讲解

这一节我们要讲的UI控件都是跟Adapter(适配器)打交道的,了解并学会使用Adapter很重要, Adapter是用来帮助填充数据的中间桥梁,简单来说就是:将各种数据以合适的形式显示到view上,提供 给用户看! 1.MVC模式的简单理解 在开始学习Adapter之前我们要来了解下这个MVC模式概…

SpringBoot——Mybatis-XML映射文件—动态SQL

使用XML映射文件配置SQL语句的规范 XML文件当中的Mapper标签里面使用的select标签的id属性是Mapper接口里面的方法名&#xff0c;resultType属性名是SQL语句要返回的对象类型。 MybatisX插件 用于管理接口方法和映射文件的关系 注解和XML配置SQL语句两种选择 动态SQL——w…

Cookie 和 Session的区别

文章目录时间&#xff1a;2023年3月23日第一&#xff1a;什么是 Cookie 和 Session ?什么是 Cookie什么是 Session第二&#xff1a;Cookie 和 Session 有什么不同&#xff1f;第三&#xff1a;为什么需要 Cookie 和 Session&#xff0c;他们有什么关联&#xff1f;第四&#x…

由本溯源,带你探索BI实时性的本质

BI 采用T1模式 BI的数据仓库架构本身就决定了对数据的实时性要求没有那么高&#xff0c;ETL的过程不可或缺&#xff0c;Extraction 抽取、Transformation 转换、Loading 加载&#xff0c;这三个环节本身就是有时间损耗的。 BI - 派可数据BI可视化分析平台 首先&#xff0c;Ex…

动态内存管理(上)——“C”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰的内容是动态内存管理噢&#xff0c;下面&#xff0c;让我们进入动态内存管理的世界吧 为什么存在动态内存分配 动态内存函数的介绍 malloc free calloc realloc 常见的动态内存错误 为什么存在动态内存分配 我们已…