【JAVA学习笔记】67 - 坦克大战1.5 - 1.6,防止重叠,记录成绩,选择是否开新游戏或上局游戏,播放游戏音乐

news2024/10/7 16:24:04

项目代码

https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter20/src

增加功能

1.防止敌人坦克重叠运动

2.记录玩家的成绩,存盘退出

3.记录当时的敌人坦克坐标,存盘退出

4.玩游戏时,可以选择是开新游戏还是继续上局游戏

1.防止敌人坦克重叠运动 

这个功能想蛮久的。因为一开始的想法是判断矩形有没有进去,但是这样判断的话,左右的矩形和上下的矩形都是一样,所以判断方向会把02或者13直接判断,后面看了老师的改用方向的角判断

1.判断是否碰撞

该方法完成了是否碰撞的判断,传入的tank和tank分别为this和enemy,testDirect代表测试方向是否可行,因为总感觉就当前方向不太合适。返回的int代表当前方向为错误方向,即走不过去

    public static int tankScopeIf(Tank tank, Tank tank1, int testDirect) {
        if (testDirect == 0) {
            switch (tank1.getDirect()) {
                case 0:
                case 2:
                    //左上角坐标[tank.getX - 20 ,tank.getY - 30]
                    if (tank.getX() - 20 >= tank1.getX() - 20
                            && tank.getX() - 20 <= tank1.getX() + 20
                            && tank.getY() - 30 >= tank1.getY() - 30
                            && tank.getY() - 30 <= tank1.getY() + 30) {
                        return 0;
                    }
                    //右上角坐标[tank.getX + 20 , tank.getY - 30]
                    if (tank.getX() + 20 >= tank1.getX() - 20
                            && tank.getX() + 20 <= tank1.getX() + 20
                            && tank.getY() - 30 >= tank1.getY() - 30
                            && tank.getY() - 30 <= tank1.getY() + 30) {
                        return 0;
                    }
                    break;
                case 1:
                case 3:
                    //左上角坐标[tank.getX - 20 ,tank.getY - 30]
                    if (tank.getX() - 20 >= tank1.getX() - 30
                            && tank.getX() - 20 <= tank1.getX() + 30
                            && tank.getY() - 30 >= tank1.getY() - 20
                            && tank.getY() - 30 <= tank1.getY() + 20) {
                        return 0;
                    }
                    //右上角坐标[tank.getX + 20 , tank.getY - 30]
                    if (tank.getX() + 20 >= tank1.getX() - 30
                            && tank.getX() + 20 <= tank1.getX() + 30
                            && tank.getY() - 30 >= tank1.getY() - 20
                            && tank.getY() - 30 <= tank1.getY() + 20) {
                        return 0;
                    }
                    break;
            }
        } else if (testDirect == 2) {
            switch (tank1.getDirect()) {
                case 0:
                case 2:
                    //左下角坐标[tank.getX - 20 ,tank.getY + 30]
                    if (tank.getX() - 20 >= tank1.getX() - 20
                            && tank.getX() - 20 <= tank1.getX() + 20
                            && tank.getY() + 30 >= tank1.getY() - 30
                            && tank.getY() + 30 <= tank1.getY() + 30) {
                        return 2;
                    }
                    //右下角坐标[tank.getX + 20 , tank.getY + 30]
                    if (tank.getX() + 20 >= tank1.getX() - 20
                            && tank.getX() + 20 <= tank1.getX() + 20
                            && tank.getY() + 30 >= tank1.getY() - 30
                            && tank.getY() + 30 <= tank1.getY() + 30) {
                        return 2;
                    }
                    break;
                case 1:
                case 3:
                    //左下角坐标[tank.getX - 20 ,tank.getY + 30]
                    if (tank.getX() - 20 >= tank1.getX() - 30
                            && tank.getX() - 20 <= tank1.getX() + 30
                            && tank.getY() + 30 >= tank1.getY() - 20
                            && tank.getY() + 30 <= tank1.getY() + 20) {
                        return 2;
                    }
                    //右下角坐标[tank.getX + 20 , tank.getY + 30]
                    if (tank.getX() + 20 >= tank1.getX() - 30
                            && tank.getX() + 20 <= tank1.getX() + 30
                            && tank.getY() + 30 >= tank1.getY() - 20
                            && tank.getY() + 30 <= tank1.getY() + 20) {
                        return 2;
                    }
                    break;
            }
        } else if (testDirect == 1) {
            switch (tank1.getDirect()) {
                case 0:
                case 2:
                    //右上角坐标[tank.getX + 30 ,tank.getY - 20]
                    if (tank.getX() + 30 >= tank1.getX() - 20
                            && tank.getX() + 30 <= tank1.getX() + 20
                            && tank.getY() - 20 >= tank1.getY() - 30
                            && tank.getY() - 20 <= tank1.getY() + 30) {
                        return 1;
                    }
                    //右下角坐标[tank.getX + 30 , tank.getY + 20]
                    if (tank.getX() + 30 >= tank1.getX() - 20
                            && tank.getX() + 30 <= tank1.getX() + 20
                            && tank.getY() + 20 >= tank1.getY() - 30
                            && tank.getY() + 20 <= tank1.getY() + 30) {
                        return 1;
                    }
                    break;
                case 1:
                case 3:
                    //右上角坐标[tank.getX + 30 ,tank.getY - 20]
                    if (tank.getX() + 30 >= tank1.getX() - 30
                            && tank.getX() + 30 <= tank1.getX() + 30
                            && tank.getY() - 20 >= tank1.getY() - 20
                            && tank.getY() - 20 <= tank1.getY() + 20) {
                        return 1;
                    }
                    //右下角坐标[tank.getX + 30 , tank.getY + 20]
                    if (tank.getX() + 30 >= tank1.getX() - 30
                            && tank.getX() + 30 <= tank1.getX() + 30
                            && tank.getY() + 20 >= tank1.getY() - 20
                            && tank.getY() + 20 <= tank1.getY() + 20) {
                        return 1;
                    }
                    break;
            }
        } else if (testDirect == 3) {
            switch (tank1.getDirect()) {
                case 0:
                case 2:
                    //左上角坐标[tank.getX - 30 ,tank.getY - 20]
                    if (tank.getX() - 30 >= tank1.getX() - 20
                            && tank.getX() - 30 <= tank1.getX() + 20
                            && tank.getY() - 20 >= tank1.getY() - 30
                            && tank.getY() - 20 <= tank1.getY() + 30) {
                        return 3;
                    }
                    //左下角坐标[tank.getX - 30 , tank.getY + 20]
                    if (tank.getX() - 30 >= tank1.getX() - 20
                            && tank.getX() - 30 <= tank1.getX() + 20
                            && tank.getY() + 20 >= tank1.getY() - 30
                            && tank.getY() + 20 <= tank1.getY() + 30) {
                        return 3;
                    }
                    break;
                case 1:
                case 3:
                    //左上角坐标[tank.getX - 30 ,tank.getY - 20]
                    if (tank.getX() - 30 >= tank1.getX() - 30
                            && tank.getX() - 30 <= tank1.getX() + 30
                            && tank.getY() - 20 >= tank1.getY() - 20
                            && tank.getY() - 20 <= tank1.getY() + 20) {
                        return 3;
                    }
                    //左下角坐标[tank.getX - 30 , tank.getY + 20]
                    if (tank.getX() - 30 >= tank1.getX() - 30
                            && tank.getX() - 30 <= tank1.getX() + 30
                            && tank.getY() + 20 >= tank1.getY() - 20
                            && tank.getY() + 20 <= tank1.getY() + 20) {
                        return 3;
                    }
                    break;
            }
        }
        return -1;
    }
}

2.接收错误方向

该方法先调用了地图范围判断,如果判断错误就把该方向计入有墙的方向,随后判断tank之间是否相互碰撞,如果传入四个值0123代表四个方向,如果返回的不是-1代表该方向无法前进,随后该方法返回一个列表

 public Vector<Integer> getSafeDirect() {
        Vector<Integer> safeDirects = new Vector<>();
        Vector<Integer> wrongDirects = new Vector<>();
        int direct;
        int cantMove;
        int haveHellDirect = -1;
        for (int i = 0; i < 4; i++) {
            safeDirects.add(i);
        }
        for (int i = 0; i < 4; i++) {
            if (Map.scopeIf(this, i)) {
                haveHellDirect = i;
                wrongDirects.add(haveHellDirect);
            }
        }

        for (int i = 0; i < enemies.size(); i++) {

            Enemy enemy = enemies.get(i);
            if (this == enemy) {
                continue;
            }
            for (int j = 0; j < 4; j++) {
                if ((cantMove = Map.tankScopeIf(this, enemy, j)) != -1) {
                    wrongDirects.add(cantMove);
                }
            }
        }
        safeDirects.removeAll(wrongDirects);
        System.out.println("不能移动的方向" + wrongDirects);
        return safeDirects;
    }

3.设置坦克方向

该方法完成了对安全方向的接受,接收到安全的方向后判断是否为空,为空代表没有方向安全,直接return,然后判断当前方向是否安全,安全就移动,然后移动的次数计数器count++,如果没有安全的方向,在安全方向里随机一个出来设置为该坦克的方向。

最后判断移动的次数,如果是5次以上就随机转向,然后重置计数

public void randomMove() {
        Vector<Integer> safeDirects = getSafeDirect();
        if (safeDirects.isEmpty()) {
            System.out.println("该敌人无法移动");
            return;
        }

        if (safeDirects.contains(this.getDirect())) {
            move();
            count++;
        }else {
            int index = (int) (Math.random() * safeDirects.size());//0-size
            setDirect(safeDirects.get(index));
        }
        if (count >= (int) (Math.random() * 40) && count > 5) {//当移动的次数大于某个值的时候,改变方向,0-39的范围
            int index = (int) (Math.random() * safeDirects.size());//0-size
            setDirect(safeDirects.get(index));
            count = 0;//计数为0
        }
    }

2.记录玩家的成绩,存盘退出

创建一个记录类,该类内实现记录击毁数量,输出字符流写入硬盘。

public class Recorder  {
    //定义变量,记录击毁坦克数量
    private static int destroyEnemy = 0;
    private static FileWriter fileWriter = null;
    private static BufferedWriter bufferedWriter = null;
    private static String recordPath = "src\\com\\yinhai\\tankgame1_5\\DestroyEnemyCount.txt";

    public static int getDestroyEnemy() {
        return destroyEnemy;
    }

    public static void setDestroyEnemy(int destroyEnemy) {
        Recorder.destroyEnemy = destroyEnemy;
    }
    public static void addDestroyEnemyCount(){
        destroyEnemy++;
    }
    public static void keepRecord() {
        try {
           bufferedWriter = new BufferedWriter(new FileWriter(recordPath,true));
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
            String format = sdf.format(new Date()); // format:将日期转换成指定格式的字符串
           bufferedWriter.write( format + " 坦克大战游戏击毁数量为 " + destroyEnemy + "\n");

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(bufferedWriter != null){
                try {
                    bufferedWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

3.记录当时的敌人坦克坐标/方向,存盘退出

在keepRecord增加功能,遍历敌人列表,保存X Y 和 方向,记得在开始游戏的时候在构造器或者能调用的地方使用set方法指向该enemies,不然一直都是null

            for (int i = 0; i < enemies.size(); i++) {
                Enemy enemy = enemies.get(i);
                if(enemy.isLive()){
                    //保存该信息
                    String record = "敌人信息" + i + " " + enemy.getX() + " "
                            + enemy.getY() + " " + enemy.getDirect() + "\r\n";
                    //写入到文件
                    bufferedWriter.write(record);
                }
            }

4.玩游戏时,可以选择是开新游戏还是继续上局游戏

可以使用对象流保存,但是最好不要更改已有的代码,所以新开一个类Node,该类拥有X Y direct,然后定义一个Vector列表保存Node,Node保存敌人的信息

该nodeHero类用于保存hero的基本信息,如击杀数等

public class Node implements Serializable {
    private int x;
    private int y;
    private int direct;
}
public class NodeHero extends Node{
    private int destroyEnemyCount;
    public NodeHero(int x, int y, int direct,int destroyEnemyCount) {
        super(x, y, direct);
        this.destroyEnemyCount = destroyEnemyCount;
    }

    public int getDestroyEnemyCount() {
        return destroyEnemyCount;
    }
}

接着在ReadCoder类内编写方法,记录信息。save方法用于保存数据到nodes内,定义输出流,将Vector<Node>(该类实现Serilizeable接口)直接输出为文件存盘。如果需要读取,调用recovery方法,该方法使用对象输入流,将该文件反序列化为对象,然后返回该nodes

    private static Vector<Enemy> enemies = null;
    private static Hero hero = null;
    private static Vector<Node> nodes = null;

    public static Vector<Node> recoveryEnemies() {
        try {
            nodes = new Vector<>();
            objectInputStream = new ObjectInputStream(new FileInputStream(recordEnemyInfoPath));
            nodes =(Vector<Node>)objectInputStream.readObject();
            System.out.println("读取完毕");
            return nodes;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            System.out.println("无上局游戏记录");
            System.exit(0);
        }
        finally {
            try {
                if (objectInputStream != null) {
                    objectInputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    public static void saveNode() throws IOException {
        nodes = new Vector<>();
        if(hero.isLife()){
            nodes.add(0,new NodeHero(hero.getX(),hero.getY(), hero.getDirect(),Recorder.destroyEnemy));
        }else{
            nodes.add(0,null);
        }

        for (int i = 0; i < enemies.size(); i++) {
            Enemy enemy = enemies.get(i);
            if(enemy.isLive()){
                nodes.add(new Node(enemy.getX(),enemy.getY(),enemy.getDirect()));
            }
        }

        if (!nodes.isEmpty()){
            objectOutputStream.writeObject(nodes);
        }


    }

然后分别在程序关闭以及开始的地方调用这两个方法,例如save方法在程序关闭时调用

public class YinhaiTankGame01 extends JFrame {
    MyPanel myPanel = null;
    public static void main(String[] args) {
        YinhaiTankGame01 yinhaiTankGame01 = new YinhaiTankGame01();


    }

    public YinhaiTankGame01(){
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入1:新游戏 2:上一局游戏");
        String key = scanner.next();
        myPanel = new MyPanel(key);
        this.add(myPanel);
        this.setSize(1600,900);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.addKeyListener(myPanel);
        new Thread(myPanel).start();
        //增加响应关闭窗口的处理
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println("检测到关闭窗口");
                Recorder.keepRecord();
                System.exit(0);
            }
        });
    }
}

使用了addWindowListener方法,当检测到关闭窗口时保存数据,在创建画板时传入key值,用于在画板的构造器内判断是否继续游戏,在该画板内如果为1,开始新游戏,将原先构造器的内容放入case语句块内即可,如果为1,调用获取记录方法,获得nodes,然后将nodes的属性分别赋给hero与enemy。

public MyPanel(String key) {
        switch (key){
            case "1":
                int xInitialize = 0;
                int yInitialize = 100;
                int count = 0;
                for (int i = 0; i < enemyNum; i++) {
                    count++;
                    if ((xInitialize = 100 * (count)) >= 1500) {
                        yInitialize += 100;
                        count = 0;
                    }
                    if (yInitialize >= 800) {
                        break;
                    }
                    Enemy enemy = new Enemy(xInitialize, yInitialize, 10);
                    hero = new Hero(800, 450, 10.0);//初始化位置
                    Thread thread = new Thread(enemy);
                    thread.start();
                    enemy.setHero(hero);
                    enemies.add(enemy);
                    enemy.setEnemies(enemies);
                    Recorder.setEnemies(enemies);
                    Recorder.setHero(hero);
                }
                break;
            case "2"://继续上次游戏
                nodes = Recorder.recoveryEnemies();
                if (nodes == null){
                    System.out.println("无上局游戏记录");
                    return;
                }
                if(nodes.get(0) == null){
                    System.out.println("hero 死亡上局游戏无法继续");
                }else{
                    NodeHero nodeHero =(NodeHero)nodes.get(0);
                    hero = new Hero(nodeHero.getX(),nodeHero.getY(),10);
                    hero.setDirect(nodeHero.getDirect());
                    Recorder.setDestroyEnemy(nodeHero.getDestroyEnemyCount());
                }
                for (int i = 1; i < nodes.size(); i++) {
                    Node node = nodes.get(i);
                    Enemy enemy = new Enemy(node.getX(),node.getY(),10);
                    enemy.setDirect(node.getDirect());
                    Thread thread = new Thread(enemy);
                    thread.start();
                    enemy.setHero(hero);
                    enemies.add(enemy);
                    enemy.setEnemies(enemies);
                    Recorder.setEnemies(enemies);
                    Recorder.setHero(hero);
                }
                break;
            default:
                System.out.println("错误的输入");
        }

5.在开始游戏的时候添加音乐

调用该API在画板绘图完成的时候启动该线程即可

package com.yinhai.tankgame1_5;

import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class AePlayWave extends Thread {
    private String filename;

    public AePlayWave(String wavfile) { //构造器 , 指定文件
        filename = wavfile;

    }

    public void run() {

        File soundFile = new File(filename);

        AudioInputStream audioInputStream = null;
        try {
            audioInputStream = AudioSystem.getAudioInputStream(soundFile);
        } catch (Exception e1) {
            e1.printStackTrace();
            return;
        }

        AudioFormat format = audioInputStream.getFormat();
        SourceDataLine auline = null;
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

        try {
            auline = (SourceDataLine) AudioSystem.getLine(info);
            auline.open(format);
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }

        auline.start();
        int nBytesRead = 0;
        //这是缓冲
        byte[] abData = new byte[512];

        try {
            while (nBytesRead != -1) {
                nBytesRead = audioInputStream.read(abData, 0, abData.length);
                if (nBytesRead >= 0)
                    auline.write(abData, 0, nBytesRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return;
        } finally {
            auline.drain();
            auline.close();
        }

    }
}

6.增加判断,如果文件不存在不开启游戏

使用File类的文件查找即可

总结:

        思路还算清晰,但是在对象流是否能精准的拿到多个对象的最后一个对象上查了很久,结论是不行,所以改用列表的方式序列化。然后就是要多写,确实不写起来很难用好面向对象的理念。重叠的想了非常久,老师的方法更简洁一点,如果当前方向走不了就随机给个方向再判断。我的想法就是全部枚举出来错误的方向,然后不走那个方向即可。

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

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

相关文章

说说对React Hooks的理解?解决了什么问题?

一、是什么 Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性 至于为什么引入hook&#xff0c;官方给出的动机是解决长时间使用和维护react过程中常遇到的问题&#xff0c;例如&#xff1a; 难以重用和共享组件中的与状态…

ChatGPT:something went wrong

今天下午不知什么原因&#xff0c;ChatGPT无法使用。我原来在使用ChatGPT for chrome&#xff0c;返回了一个答案&#xff0c;后来在网页端无法使用&#xff0c;以为是这个chrome插件泄露API KEY导致的。注销账号&#xff0c;删除API KEY后&#xff0c;wrong问题仍然存在。 我…

读程序员的制胜技笔记08_死磕优化(上)

1. 过早的优化是万恶之源 1.1. 著名的计算机科学家高德纳(Donald Knuth)的一句名言 1.2. 原话是&#xff1a;“对于约97%的微小优化点&#xff0c;我们应该忽略它们&#xff1a;过早的优化是万恶之源。而对于剩下的关键的3%&#xff0c;我们则不能放弃优化的机会。” 2. 过早…

12 # 手写 findIndex 方法

findIndex 的使用 findIndex() 方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回 -1。 <script>var arr [1, 3, 5, 7, 8];var result arr.findIndex(function (ele, index, array) {console.log("ele----->", ele);conso…

【Java】SPI在Java中的实现与应用

一、SPI的概念 1.1、什么是API&#xff1f; API在我们日常开发工作中是比较直观可以看到的&#xff0c;比如在 Spring 项目中&#xff0c;我们通常习惯在写 service 层代码前&#xff0c;添加一个接口层&#xff0c;对于 service 的调用一般也都是基于接口操作&#xff0c;通…

已解决:rm: 无法删除“/opt/module/zookeeper-3.4.10/zkData/zookeeper_server.pid“: 权限不够

解决&#xff1a; ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg Stopping zookeeper ... /opt/module/zookeeper-3.4.10/bin/zkServer.sh: 第 182 行:kill: (4149) - 不允许的操作 rm: 无法删除"/opt/module/zooke…

开发知识点-Python

Python从小白到入土 python渗透测试安全工具开发锦集Python安全工具编程基础第一章 Python在网络安全中的应用第一节 Python黑客领域的现状第二节 我们可以用Python做什么第三节 第一章课程内容总结 第二章 python安全应用编程入门第一节 Python正则表达式第二节 Python Web编程…

C++二分查找算法:阶乘函数后 K 个零

涉及知识点 二分查找 数学 题目 f(x) 是 x! 末尾是 0 的数量。回想一下 x! 1 * 2 * 3 * … * x&#xff0c;且 0! 1 。 例如&#xff0c; f(3) 0 &#xff0c;因为 3! 6 的末尾没有 0 &#xff1b;而 f(11) 2 &#xff0c;因为 11! 39916800 末端有 2 个 0 。 给定 k&a…

Python--列表及其应用场景

1.为什么需要列表 思考&#xff1a;有一个人的姓名(laowang)怎么书写存储程序&#xff1f; 用 变量。如&#xff1a;name laowang 但是&#xff0c;如果要记录很多人的名字&#xff0c;怎么办&#xff1f; 思考&#xff1a; 如果一个班级100位学生&#xff0c;每个人的…

17 Linux 中断

一、Linux 中断简介 1. Linux 中断 API 函数 ① 中断号 每个中断都有一个中断号&#xff0c;通过中断号可以区分出不同的中断。在 Linux 内核中使用一个 int 变量表示中断号。 ② request_irq 函数 在 Linux 中想要使用某个中断是需要申请的&#xff0c;request_irq 函数就是…

【Unity ShaderGraph】| 如何快速制作一个炫酷的 全息投影效果

前言 【Unity ShaderGraph】| 如何快速制作一个炫酷的 全息投影效果一、效果展示二、 全息投影效果 前言 本文将使用ShaderGraph制作一个 炫酷的 全息投影效果 &#xff0c;可以直接拿到项目中使用。对ShaderGraph还不了解的小伙伴可以参考这篇文章&#xff1a;【Unity Shader…

mac 卸载第三方输入法

输入法设置里的移除&#xff0c;并不是真的卸载&#xff0c;点击还是能添加回来 在活动监视器里强制退出此输入法在访达界面使用快捷键 ShiftcommandG在弹出的对话框内输入以下路径&#xff08;/资源库/Input Methods&#xff09;&#xff0c;再点击下面的前往找到你要卸载的输…

HadSky+内网穿透打造个人专属社区论坛并远程访问

文章目录 前言1. 网站搭建1.1 网页下载和安装1.2 网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3 Cpolar稳定隧道&#xff08;本地设置&#xff09;2.4 公网访问测试 总结 前言 经过多年的基础…

盘点那些开发中经常用到的git命令

入职第一天 配置邮箱账号 git config —global user.email "XXXX" git config —global user.name "XXXX" 生成公钥 ssh-keygen -t rsa -C "你的邮箱"生成的文件默认在c盘:/用户/当前用户/.ssh文件夹下&#xff0c;也可以指定文件 打开git网页&…

MySQL(12):MySQL数据类型

MySQL中的数据类型 常见数据类型的属性&#xff1a; 整数类型 整数类型一共有 5 种&#xff0c;包括 TINYINT、SMALLINT、MEDIUMINT、INT&#xff08;INTEGER&#xff09;和 BIGINT。 CREATE TABLE test_int1 ( X TINYINT, y SMALLINT, z MEDIUMINT, m INT, n BIGINT );…

Postgresql数据类型-时间类型

PostgreSQL对时间、日期数据类型的支持丰富而灵活&#xff0c;本节介绍PostgreSQL支持的时间、日期类型&#xff0c;及其操作符和常用函数。 PostgreSQL支持的时间、日期类型如表所示。 我们通过一个简单的例子理解这几个时间、日期数据类型&#xff0c;先来看看系统自带的now…

高性能网络编程 - 解读5种I/O模型

文章目录 服务端处理网络请求流程图基础概念阻塞调用 vs 非阻塞调用同步处理 vs 异步处理阻塞、非阻塞 和 同步、异步的区别recvfrom 函数 五种I/O模型I/O模型1&#xff1a;阻塞式 I/O 模型(blocking I/O&#xff09;I/O模型2&#xff1a;非阻塞式 I/O 模型(non-blocking I/O&a…

实用技巧:嵌入式人员使用http服务模拟工具模拟http服务器测试客户端get和post请求

文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/134305752 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结…

卡尔曼滤波EKF

目录 一、概述 二、卡尔曼滤波的5个公式 三、应用案例&#xff1a;汽车运动 四、应用案例&#xff1a;温度估计 五、总结 一、概述 初学者对于卡尔曼滤波5个公式有点懵&#xff0c;本文先接地气地介绍5个公式&#xff0c;然后举两个常用例子加强理解&#xff0c;同时附有M…

杰里6969系列控制RGB彩灯模式

1、任务目标 实现可以接收到APP传输过来的数据&#xff0c;可以通过传输的数据前几个字节识别到所需要控制的模式&#xff0c;然后提取数据的后几个字节来分别对RGB灯进行不同的的PWM波控制&#xff0c;从而实现跳变和渐变的效果。 2.跳变&#xff08;分布调试记录&#xff09…