利用C#实现贪吃蛇

说明

本文根据B站up主唐老狮的课程所学所记

目录

  • 说明
    • 本文根据B站up主唐老狮的课程所学所记
  • UML
  • 面向对象七大原则
    • 总体实现目标
    • 单一职责原则(SRP,Single Responsibility Principle)
    • 开闭原则(OCP,Open-Closed Principle)
    • 里氏替换原则(LSP,Liskov Substitution Principle)
    • 依赖倒转原则(DIP,Dependence Inversion Principle)
    • 迪米特原则(LoP of Demeter)
    • 接口分离原则(ISP,Interface Segregation Principle)
    • 合成复用原则(CRP,Composite Reuse Principle)
  • UML类图
  • Game对象和场景更新接口
  • 实现多场景切换
  • 游戏对象基类的实现
  • 继承游戏对象基类的对象
  • 地图对象
  • 蛇对象
  • 蛇移动
  • 蛇转向
  • 撞墙撞身体
  • 吃食物
  • 长身体

UML

关联: 如类A会有一个类B成员作为它的成员变量
直接关联: 如母鸡类中有一个行为是下蛋,它和气候直接关联
聚合: 如地图类聚合围墙类,鸟群类聚合大雁类
依赖关系: 如动物类依赖于空气类和水类
复合: 如公司类包含各种部门类,部门类和公司类的关系就是复合关系

面向对象七大原则

总体实现目标

高内聚、低耦合,使程序模块的可重用性、移植性增强

高内聚低耦合
从类角度来看:减少类内部对其他类的调用
从功能模块来看:减少模块之间的交互复杂度

单一职责原则(SRP,Single Responsibility Principle)

类被修改的几率很大,因此应该专注于单一的功能。如果把多个功能放在同一个类中,功能之间就形成了关联,改变其中一个功能,有可能中止另一个功能。
例如:假设程序、策划、美术三个工种是三个类,他们应该各司其职,在程序世界中只应该做自己应该做的事情。

开闭原则(OCP,Open-Closed Principle)

对拓展开放,对修改关闭

拓展开放:模块的行为可以被拓展从而满足新的需求
修改关闭:不允许修改模块的源代码(或者尽量使修改最小化)

例如:继承就是最典型的开闭原则的体现,可以通过添加新的子类和重写父类的方法来实现。

里氏替换原则(LSP,Liskov Substitution Principle)

任何父类出现的地方,子类都可以替代
例如:用父类容器装载子类对象,因为子类对象包含了父类的所有内容。

依赖倒转原则(DIP,Dependence Inversion Principle)

要依赖于抽象,不要依赖于具体的实现。
例如:玩家对象抽象出开枪这一行为
在这里插入图片描述

迪米特原则(LoP of Demeter)

又称最少知识原则,一个对象应当对其他对象尽可能少的了解,不要和陌生人说话
例如:一个对象中的成员,要尽可能少的直接和其他类建立关系,目的是降低耦合性。

接口分离原则(ISP,Interface Segregation Principle)

不应该强迫别人依赖他们不需要使用的方法,一个接口不需要提供太多的行为,一个接口应该尽量只提供一个对外的功能,让别人去选择需要实现什么样的行为,而不是把所有的行为都封装到一个接口当中。
例如:飞行接口、走路接口、跑步接口等等虽然都是移动的行为,但是我们应该把他们分为一个一个单独的接口,让别人去选择使用。

合成复用原则(CRP,Composite Reuse Principle)

尽量使用对象组合,而不是继承来达到复用的目的,继承关系是强耦合,组合关系是低耦合。
例如:脸应该是眼镜、鼻子、嘴巴、耳朵的组合,而不是依次的继承。角色和装备也应该是组合,而不是继承。
注意:不能盲目的使用合成复用原则,要在遵循迪米特原则的前提下。


UML类图

在这里插入图片描述

Game对象和场景更新接口

1、创建“贪吃蛇”项目,创建“c1”文件
2、在“c1”文件下创建“Game”类
3、在“c1”文件下创建“ISceneUpdate”接口
4、对“ISceneUpdate”添加Update()方法
在这里插入图片描述
5、添加“Game”类所需成员变量

//窗口长宽
public int w = 80;
public int h = 20;
//当前选中场景
public ISceneUpdate nowScene;

6、构造函数实现

public Game()
{Console.CursorVisible = false;//鼠标是否隐藏Console.SetWindowSize(w, h);//设置窗口大小Console.SetBufferSize(w, h);//设置缓冲区大小
}

7、实现游戏主循环:添加start函数

//实现游戏主循环:负责游戏场景逻辑的更新
public void start()
{while(true){//如果当前场景不为空就更新if(nowScene != null){nowScene.Update();}}
}

8、场景切换
①添加E_SceneType枚举

//场景类型枚举
enum E_SceneType
{Begin,Game,End
}

②添加ChangeScene函数

//场景切换
public void ChangeScene(E_SceneType type)
{
//切场景之前应该把上一个场景的绘制内容擦掉Console.Clear();switch(type){case E_SceneType.Begin:break;case E_SceneType.Game:break;case E_SceneType.End:break;}
}

修改文件展示:
Game.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace 贪吃蛇.c1
{//场景类型枚举enum E_SceneType{Begin,Game,End}class Game{//窗口长宽public int w = 80;public int h = 20;//当前选中场景public ISceneUpdate nowScene;public Game(){Console.CursorVisible = false;//鼠标是否隐藏Console.SetWindowSize(w, h);//设置窗口大小Console.SetBufferSize(w, h);//设置缓冲区大小}//实现游戏主循环:负责游戏场景逻辑的更新public void start(){while(true){//如果当前场景不为空就更新if(nowScene != null){nowScene.Update();}}}//场景切换public void ChangeScene(E_SceneType type){//切场景之前应该把上一个场景的绘制内容擦掉Console.Clear();switch(type){case E_SceneType.Begin:break;case E_SceneType.Game:break;case E_SceneType.End:break;}}}
}

ISceneUpdate.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace 贪吃蛇.c1
{interface ISceneUpdate{void Update();}
}

实现多场景切换

1、创建“c2”文件,添加游戏场景类GameScene,为了继承ISceneUpdate,则需要引用命名空间

using 贪吃蛇.c1;

继承接口ISceneUpdate

namespace 贪吃蛇.c2
{class GameScene : ISceneUpdate{public void Update(){Console.SetCursorPosition(0, 0);Console.Write("游戏场景");}}
}

3、添加开始和结束场景基类BeginOrEndBaseScene,并继承ISceneUpdate

using 贪吃蛇.c1;namespace 贪吃蛇.c2
{class BeginOrEndBaseScene : ISceneUpdate{public int nowSelIndex = 0;public string strTitle;public string strOne;//表示public void Update(){Console.SetCursorPosition(0, 0);Console.Write("开始或结束场景");}}
}

4、修改Game类中的ChangeScene方法

public void ChangeScene(E_SceneType type)
{//切场景之前应该把上一个场景的绘制内容擦掉Console.Clear();switch(type){case E_SceneType.Begin:nowScene = new BeginOrEndBaseScene();//当前场景为开始或者结束break;case E_SceneType.Game:nowScene = new GameScene();//当前场景为游戏break;case E_SceneType.End:nowScene = new BeginOrEndBaseScene();break;}
}

在Game类中的构造函数调用ChangeScene方法

ChangeScene(E_SceneType.Begin);

主函数实现如下
在这里插入图片描述
运行测试如下
在这里插入图片描述
5、开始和结束基类逻辑实现
①首先将Game中的w、h变量改为const常量,方便通过Game直接调用
②将BeginOrEndBaseScene改为抽象类,添加抽象方法,并将该类中的成员变量设置为protected。

public abstract void EnterJDoSomething();//按下j键的逻辑

③实现BeginOrEndBaseScene中的Update方法

public void Update()
{//将控制台的前景色设为白色Console.ForegroundColor = ConsoleColor.White;//显示标题Console.SetCursorPosition(Game.w / 2 - strTitle.Length, 5);//设置光标在窗口宽度的一半减去字体长度的位置,第五行Console.Write(strTitle);//打印标题//显示第一个选项Console.SetCursorPosition(Game.w / 2 - strOne.Length, 8);Console.ForegroundColor = nowSelIndex == 0 ? ConsoleColor.Red : ConsoleColor.White;//根据索引不同调整选中选项颜色Console.Write(strOne);//显示第二个选项Console.SetCursorPosition(Game.w / 2 - 4, 10);Console.ForegroundColor = nowSelIndex == 1 ? ConsoleColor.Red : ConsoleColor.White;Console.Write("游戏结束");//检测输入switch (Console.ReadKey(true).Key) {case ConsoleKey.W://按下w键--nowSelIndex;if(nowSelIndex < 0){nowSelIndex = 0;}break;case ConsoleKey.S://按下s键++nowSelIndex;if (nowSelIndex > 0)nowSelIndex = 1;break;case ConsoleKey.J://按下j键EnterJDoSomething();break;}
}

④将Game类中改变场景ChangeScene方法实例化BeginOrEndBaseScene类注释掉,因为该类已经是一个抽象类,不能被实例化。
在这里插入图片描述
6、实现开始场景BeginScene类
①将BeginScene类继承BeginOrEndBaseScene,并实现构造函数将strTitle和strOne初始化

class BeginScene : BeginOrEndBaseScene
{public BeginScene() {strTitle = "贪吃蛇";strOne = "开始游戏";}public override void EnterJDoSomething(){}
}

②为了能在此类中调用ChangeScene函数,特将Game类中的ChangeScene函数设为static,由于静态方法中不能调用成员变量,则将nowScene也设为静态变量。
③实现EnterJDoSomething方法

public override void EnterJDoSomething()
{if(nowSelIndex == 0){Game.ChangeScene(E_SceneType.Game);}else{Environment.Exit(0);}
}

④将Game类中改变场景开始被注释掉的代码改为
在这里插入图片描述
运行代码,此时按下w或者s键盘可上下切换,且在开始游戏选项中按下j键可进入游戏场景。
在这里插入图片描述
在这里插入图片描述
7、实现结束场景EndScene类

class EndScene : BeginOrEndBaseScene
{public EndScene() {strTitle = "游戏结束";strOne = "回到开始界面";}public override void EnterJDoSomething(){if (nowSelIndex == 0){Game.ChangeScene(E_SceneType.Begin);}else{Environment.Exit(0);}}
}

在这里插入图片描述
在这里插入图片描述
运行代码,初始出现在结束场景。
在这里插入图片描述

游戏对象基类的实现

在这里插入图片描述

1、创建c3文件夹,创建IDraw接口,添加Draw方法
在这里插入图片描述
2、创建一个类,改名为Position,作为位置结构体

struct Position
{public int x;public int y;  public Position(int x, int y){this.x = x;this.y = y;}public static bool operator ==(Position p1,Position p2){if(p1.x == p2.x && p1.y == p2.y){return true;}return false;}public static bool operator !=(Position p1, Position p2){if (p1.x == p2.x && p1.y == p2.y){return false;}return true;}
}

3、创建GameObject类

abstract class GameObject : IDraw
{public Position pos;public abstract void Draw();
}

继承游戏对象基类的对象

1、实现地图墙壁类Wall
①创建c4文件夹,添加类Wall

class Wall : GameObject
{public Wall(int x,int y) {pos = new Position(x,y);}public override void Draw(){Console.SetCursorPosition(pos.x, pos.y);Console.ForegroundColor = ConsoleColor.Red;Console.WriteLine("🤡");}
}

2、实现食物类Food

class Food : GameObject
{public Food(int x,int y){pos = new Position(x,y);}public override void Draw(){Console.SetCursorPosition(pos.x, pos.y);Console.ForegroundColor = ConsoleColor.Cyan;Console.WriteLine("🐘");}
}

3、实现蛇身子类和蛇身枚举

enum E_SnakeBody_Type
{Head,Body
}
class SnakeBody : GameObject
{private E_SnakeBody_Type type;public SnakeBody(E_SnakeBody_Type type,int x,int y){this.type = type;this.pos = new Position(x,y);}public override void Draw(){Console.SetCursorPosition(pos.x,pos.y);Console.ForegroundColor = type == E_SnakeBody_Type.Head ? ConsoleColor.Green : ConsoleColor.Red;Console.WriteLine(type == E_SnakeBody_Type.Head ? "😍" : "🔞");}
}

地图对象

1、创建c5文件夹,添加地图类Map

class Map : IDraw
{private Wall[] walls;public Map(){walls = new Wall[Game.w + (Game.h - 3) * 2];int index = 0;for (int i = 0; i < Game.w; i += 2){walls[index] = new Wall(i, 0);++index;}for (int i = 0; i < Game.w; i += 2){walls[index] = new Wall(i, Game.h - 2);++index;}for (int i = 1; i < Game.h - 2; i++){walls[index] = new Wall(0, i);++index;}for (int i = 1; i < Game.h - 2; i++){walls[index] = new Wall(Game.w - 2, i);++index;}}public void Draw(){for (int i = 0; i < walls.Length; i++){walls[i].Draw();}}

2、修改游戏场景类GameScene

class GameScene : ISceneUpdate
{private Map map;public GameScene(){map = new Map();}public void Update(){map.Draw();}
}

蛇对象

1、创建c6文件夹,添加蛇类Snake

class Snake : IDraw
{SnakeBody[] bodys;int nowNum;public Snake(int x,int y){bodys = new SnakeBody[200];bodys[0] = new SnakeBody(E_SnakeBody_Type.Head,x,y);nowNum = 1;}public void Draw(){for(int i = 0;i < nowNum;i++){bodys[i].Draw();}}
}

2、修改游戏场景类GameScene

class GameScene : ISceneUpdate
{private Map map;Snake snake;public GameScene(){map = new Map();snake = new Snake(40,10);}public void Update(){map.Draw();snake.Draw();}
}

蛇移动

1、修改蛇类Snake
①添加方向枚举
②初始化枚举变量
③添加Move方法

enum E_MoveDir
{up,down, left, right   
}
class Snake : IDraw
{SnakeBody[] bodys;int nowNum;E_MoveDir dir;public Snake(int x,int y){bodys = new SnakeBody[200];bodys[0] = new SnakeBody(E_SnakeBody_Type.Head,x,y);nowNum = 1;dir = E_MoveDir.up;}public void Move(){SnakeBody lastBody = bodys[nowNum - 1];Console.SetCursorPosition(lastBody.pos.x,lastBody.pos.y);Console.WriteLine("  ");switch (dir){case E_MoveDir.up:--bodys[0].pos.y;break;case E_MoveDir.down:++bodys[0].pos.y;break;case E_MoveDir.left:bodys[0].pos.x -= 2;break;case E_MoveDir.right:bodys[0].pos.x += 2;break;}}public void Draw(){for(int i = 0;i < nowNum;i++){bodys[i].Draw();}}
}

2、修改游戏场景代码GameScene

class GameScene : ISceneUpdate
{private Map map;Snake snake;int updateIndex;public GameScene(){map = new Map();snake = new Snake(40,10);}public void Update(){if(updateIndex % 99999999 == 0){map.Draw();snake.Move();snake.Draw();updateIndex = 0;}updateIndex++;}
}

蛇转向

1、在Snake类中添加ChangeDir方法

public void ChangeDir(E_MoveDir dir)
{//不转向的情况if (this.dir == dir ||nowNum > 1 && (this.dir == E_MoveDir.left && dir == E_MoveDir.right|| this.dir == E_MoveDir.right && dir == E_MoveDir.left || this.dir == E_MoveDir.up && dir == E_MoveDir.down|| this.dir == E_MoveDir.down && dir == E_MoveDir.up)){return;}//否则转向this.dir = dir;
}

2、在游戏场景类GameScene中修改Update

public void Update()
{if(updateIndex % 22222 == 0){map.Draw();snake.Move();snake.Draw();updateIndex = 0;}updateIndex++;if(Console.KeyAvailable)//按键保持激活的时候{switch(Console.ReadKey(true).Key){case ConsoleKey.W:snake.ChangeDir(E_MoveDir.up);break;case ConsoleKey.S:snake.ChangeDir(E_MoveDir.down);break;case ConsoleKey.A:snake.ChangeDir(E_MoveDir.left);break;case ConsoleKey.D:snake.ChangeDir(E_MoveDir.right);break;}}
}

撞墙撞身体

1、Snake类中添加CheckEnd函数

public bool CheckEnd(Map map)
{for(int i = 0;i < map.walls.Length;i++){if (bodys[0].pos == map.walls[i].pos)//判断头与墙的位置是否相等{return true;}}for(int i = 1;i < nowNum;i++){if (bodys[0].pos == bodys[i].pos) return true;//判断头与身体的位置是否相等}return false;
}

2、将Map中walls数组改为public
3、GameScene中的Update添加如下代码
在这里插入图片描述

吃食物

1、在Snake类中添加CheckSamePos函数

public bool CheckSamePos(Position p)
{for (int i = 0; i < nowNum; i++){if (bodys[i].pos == p)//判断传入参数是否和蛇位置相等return true;}return false;
}

2、在Food类中添加RandomPos函数

public void RandomPos(Snake snake)//用于随机位置生成食物
{Random r = new Random();int x = r.Next(2, (Game.w / 2 - 1) * 2);int y = r.Next(1, Game.h - 4);pos = new Position(x, y);if(snake.CheckSamePos(pos)){RandomPos(snake); }
}

3、更新Food构造函数

public Food(Snake snake)
{RandomPos(snake);
}

4、在Snake类中添加CheckEatPos函数

public void CheckEatFood(Food food)
{if (bodys[0].pos == food.pos)food.RandomPos(this);
}

5、在GameScene中的Update方法中加入如下代码
在这里插入图片描述

长身体

1、在Snake类中添加AddBody方法

public void AddBody()
{SnakeBody frontBody = bodys[nowNum - 1];bodys[nowNum] = new SnakeBody(E_SnakeBody_Type.Body, frontBody.pos.x,frontBody.pos.y);++nowNum;
}

2、更新Snake中的CheckEatFood方法
在这里插入图片描述
3、更新Snake中的Move方法
在这里插入图片描述

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

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

相关文章

Flume基础知识(二):Flume安装部署

1. Flume 安装部署 1.1 安装地址 &#xff08;1&#xff09;Flume 官网地址&#xff1a;Welcome to Apache Flume — Apache Flume &#xff08;2&#xff09;文档查看地址&#xff1a;Flume 1.11.0 User Guide — Apache Flume &#xff08;3&#xff09;下载地址&#xf…

==和equals

和equals的作用 基本数据类型,基本数据类型比较的是值,引用的数据类型其实也是比较的是值,但是引用的数据类型 int x 10; int y 10; String str1 new String("abc"); String str2 new String("abc"); System.out.println(x y); // true System.out.…

python基础语法(一)变量

目录 使用变量 变量的类型 整数 浮点数 字符串 布尔 其他 使用变量 读取变量的值 a 10 print(a) 修改变量的值 a20 print(a) 在Python中&#xff0c;需要注意的是&#xff0c;修改变量也是使用运算&#xff0c;看起来和定义变量没有明显区别 当然&#xff0c;也可…

[数据结构]链栈的创建,入栈和出栈

栈是一种在栈顶压入和弹出的数据结构&#xff0c;所以只在一端进行操作.为了减小遍历开支&#xff0c;所以链栈一般在首元节点处进行插入&#xff08;入栈&#xff09;. #include <stdio.h> #include <stdlib.h>typedef struct Node {int data;struct Node* next;…

qiankun 公共依赖

1、提取公共依赖的目的 减少相同资源的重复加载资源版本不同步打包文件庞大2、如何提取公共依赖 基本思路&#xff1a;1、相同依赖 采用 CDN 的方式加载&#xff0c;并把 所有依赖的 CDN 链接 统一放到一个文件中进行管理 2、把存放 CDN 链接的文件&#xff0c;引入到 vue.conf…

创意与技术的结晶:AI魔法绘图与中文描述的完美结合

在人类文明的长河中&#xff0c;创意与技术一直是推动发展的重要动力。随着科技的日新月异&#xff0c;人工智能&#xff08;AI&#xff09;在创意领域的应用逐渐崭露头角&#xff0c;而AI魔法绘图与中文描述的结合&#xff0c;更是将这一趋势推向了新的高度。AI魔法绘图是一种…

NNote插件:让网络阅读变得更高效,轻松同步至Notion笔记

NNote笔记 在这个互联网时代&#xff0c;我们每天都在浏览器中阅读大量的文章和资讯&#xff0c;时常会遇到让人眼前一亮的观点和想法。然而&#xff0c;当我们试图将这些精彩内容记录下来时&#xff0c;却常常感受到复制粘贴的繁琐。为了解决这个问题&#xff0c;NNote插件应运…

HarmonyOS 应用开发学习笔记 ets自定义组件及其引用 @Component自定义组件

Component注解的作用是用来构建自定义组件 Component组件官方文档 自定义组件具有以下特点&#xff1a; 可组合&#xff1a;允许开发者组合使用系统组件、及其属性和方法。 可重用&#xff1a;自定义组件可以被其他组件重用&#xff0c;并作为不同的实例在不同的父组件或容器…

【深度学习每日小知识】数据增强

数据增强是通过对原始数据进行各种转换和修改来人工生成附加数据的过程&#xff0c;旨在增加机器学习模型中训练数据的大小和多样性。这对于计算机视觉领域尤为重要&#xff0c;因为图像经常被用作输入数据。 计算机视觉中的数据增强 数据增强的主要目标是解决过拟合问题&…

Java 开发环境搭建

什么是 JDK 和 JRE&#xff1f; JDK &#xff08;Java Development Kit&#xff09;&#xff1a;是 Java 程序开发工具包&#xff0c;包含 JRE 和开发人员使用的工具JRE&#xff08;Java Runtime Environment&#xff09;&#xff1a;是 Java 程序的运行时环境&#xff0c;包含…

Javaweb之Mybatis的基础操作之新增和更新操作的详细解析

1.4 新增 功能&#xff1a;新增员工信息 1.4.1 基本新增 员工表结构&#xff1a; SQL语句&#xff1a; insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (songyuanqiao,宋远桥,1,1.jpg,2,2012-10-09,2,2022-10-…

HR_net逐步实现过程

1.numpy实现数组卷积操作 这里是一个矩阵&#xff0c;换个图试一下 import numpy as np #输入数组 input_imagenp.array([[1,2,3],[4,5,6],[7,8,9]]) #卷积核 kernelnp.array([[1,0],[0,1]]) #卷积操作 output_imagenp.zeros((2,2)) for i in range(2):for j in range(2):out…

Spark内核解析-内存管理7(六)

1、Spark内存管理 Spark 作为一个基于内存的分布式计算引擎&#xff0c;其内存管理模块在整个系统中扮演着非常重要的角色。理解 Spark 内存管理的基本原理&#xff0c;有助于更好地开发 Spark 应用程序和进行性能调优。本文中阐述的原理基于 Spark 2.1 版本。 在执行 Spark 的…

git 本地仓库

本地仓库 start.bat 启动

win7系统报错msvcp140.dll丢失的多种解决方法分享

在Windows 7操作系统中&#xff0c;msvcp140.dll是一个非常重要的动态链接库文件&#xff0c;它负责许多应用程序的正常运行。然而&#xff0c;由于各种原因&#xff0c;我们可能会遇到丢失msvcp140.dll的问题。当msvcp140.dll文件丢失或损坏时&#xff0c;可能会导致程序无法启…

OCS2 入门教程(三)- 最优控制模块

系列文章目录 前言 在本页中&#xff0c;我们将为您提供如何定义 MPC 问题的一些提示。在 OCS2 中&#xff0c;OptimalControlProblem 结构定义了优化问题的主要组成部分&#xff0c;即动力学、成本和约束条件。 除此之外&#xff0c;您可能还希望为 MPC 提供一些参考轨迹、预定…

Apache Commons Email在邮件发送中的应用

第1章&#xff1a;简介 大家好&#xff0c;我是小黑&#xff0c;今天咱们聊聊Apache Commons Email这个库&#xff0c;它在发送邮件方面可谓是小而美的利器。Apache Commons Email基于JavaMail API&#xff0c;但它提供了更简洁、更易用的接口&#xff0c;让咱们在处理电子邮件…

MySQL-DCL

DCL是数据控制语言&#xff0c;用来管理数据库用户&#xff0c;控制数据库的访问权限。 管理用户&#xff1a;管理哪些用户可以访问哪些数据库 1.查询用户 USE mysql; SELECT * FROM user; 注意&#xff1a; MySQL中用户信息和用户的权限信息都是记录在mysql数据库的user表中的…

Python重温笔记番外篇

1. 写在前面 今天这篇文章是python重温笔记的番外&#xff0c;整理一些面试中的问题以及遇到过的一些坑&#xff0c; 正好借着这个机会把前面的知识进行一个串联&#xff0c; 要不然这些知识很容易就会遗忘&#xff0c; 毕竟知识多而又不太容易常用到。 涉及到的知识包括列表推…

ARCGIS PRO SDK 使用条件管理 Pro UI

ARCGIS PRO UI简单介绍以下&#xff1a; 第一步&#xff1a;在Config.daml中在</AddInfo>标签下加上条件<conditions>标签&#xff08;必须添加的&#xff09; <conditions><!-- 定义条件 &#xff0c;此处定义了两个--Tab 另一个为 group><insert…