当前位置: 首页 > news >正文

Godot 4 教程《勇者传说》依赖注入 学习笔记(0):环境配置

文章目录

  • 前言
  • 相关地址
  • 环境配置
  • 初始化环境配置
    • 文件夹结构
    • 代码结构
    • 代码运行
  • 资源文件导入
  • 像素风格窗口环境设置
  • 背景设置,Tileap使用
    • 自动TileMap
  • 人物场景
  • 动画节点添加
    • 站立节点添加
    • 移动动画添加
  • 通过依赖注入获取Godot的全局属性
    • 项目声明
  • 当前项目逻辑讲解
  • 角色下降
    • 添加代码
    • 位置问题的思考
      • 在Node2D上面挂载Lable节点
      • 在CharacterBody2D下面挂载
      • 解决方案
        • 修改代码
        • 动画节点的问题,需要重新绑定
        • 为什么我要这么写
  • 动画效果
    • 初始化AnimationPlayer
  • 输入映射
    • 获取输入
      • 简单移动
      • 完善输入和添加动画
      • 完善跳跃手感

前言

我之前解决了C# 的IOC的配置,现在来认真学习一个完整的Godot 项目。我看B站上面这个教程非常的好,所以打算用C# 去复刻一下,使用IOC依赖注入的想法。

相关地址

十分钟制作横版动作游戏|Godot 4 教程《勇者传说》#0

人物素材

环境素材

Gclove2000/GodotNet_LegendOfPaladin

在这里插入图片描述

环境配置

  • Windows 10
  • .net core 8.0
  • Visual Studio 2022
  • godot.net 4.2.1

初始化环境配置

Godot.NET C# 工程化开发(1):通用Nuget 导入+ 模板文件导出,包含随机数生成,日志管理,数据库连接等功能

在这里插入图片描述

文件夹结构

  • Godot:Godot项目+主要游戏逻辑代码
  • GodotProgram:帮助类

代码结构

  • GodotNet_LegndOfPaladin:Godot主要逻辑
    • SceneModels:场景IOC对象
    • SceneScirpts:场景对应脚本
    • Util: Godot API帮助类
      • PackedSceneHelper:打包场景加载
    • Program:IOC容器
  • GodotProgram:C# 主要逻辑
    • Assets:资产文件
    • DB:数据库对象
    • Interfaces:接口
    • Service:服务
    • Utils:帮助类

代码运行

在这里插入图片描述
在这里插入图片描述

资源文件导入

人物素材

环境素材

在这里插入图片描述

在这里插入图片描述

像素风格窗口环境设置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

背景设置,Tileap使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

自动TileMap

Godot 官方2D C#重构(3):TileMap使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
大致实现效果

在这里插入图片描述
绘制TimeMap地形需要比较强的熟练度。多多联系即可

在这里插入图片描述
在这里插入图片描述

人物场景

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
长按左键选择站立动画

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

动画节点添加

站立节点添加

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
点击6次,添加6个关键帧
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

移动动画添加

和上面的一样

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

通过依赖注入获取Godot的全局属性

Godot的全局属性是通过字符串的方式获取的,这非常容易出问题。而且我们也希望这种配置信息能在项目启动的时候就获取

在这里插入图片描述

Godot ProjectSettings 字符串对应数据

项目声明

    public class GodotProjectSettingHelper{private NlogHelper nlogHelper;public readonly float Gravity = 0;public GodotProjectSettingHelper(NlogHelper nlogHelper){this.nlogHelper = nlogHelper;Gravity = (float)ProjectSettings.GetSetting("physics/2d/default_gravity");}}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

当前项目逻辑讲解

在这里插入图片描述
在这里插入图片描述
所以我们新建一个场景的逻辑是

  • 新增XXX.tscn
  • 挂载XXXScene.sc脚本
  • IOC注入XXXSceneModel.cs 类
  • PackedSceneHelper添加对应的PackedScene

详情请看我的Github源码

Gclove2000/GodotNet_LegendOfPaladin

角色下降

在这里插入图片描述

在这里插入图片描述

添加代码

public class PlayerSceneModel : ISceneModel
{private NlogHelper nlogHelper;private GodotProjectSettingHelper godotProjectSettingHelper;public PlayerSceneModel(NlogHelper nlogHelper,GodotProjectSettingHelper godotProjectSettingHelper) {this.nlogHelper = nlogHelper;this.godotProjectSettingHelper = godotProjectSettingHelper;}private CharacterBody2D characterBody2D;public override void Process(double delta){//给角色一个速度,因为重力是加速度,所以角色的速度会不断的增加。characterBody2D.Velocity += new Vector2(0, godotProjectSettingHelper.Gravity * (float)delta);//让物体以这个速度进行移动characterBody2D.MoveAndSlide();nlogHelper.Debug($"x:{characterBody2D.Velocity.X},y:{characterBody2D.Velocity.Y}");}public override void Ready(){nlogHelper.Debug($"当前重力值为:{godotProjectSettingHelper.Gravity}");characterBody2D = this.Sence.GetNode<CharacterBody2D>("CharacterBody2D");}
}

在这里插入图片描述

位置问题的思考

我们知道CharacterBody2D就是为了获取CollisionShape2D的位置。因为他的位置取决于重力,物理碰撞,加速度等多方面因素。相当于他的位置是自动变化的

在Node2D上面挂载Lable节点

在这里插入图片描述
在这里插入图片描述

在CharacterBody2D下面挂载

在这里插入图片描述
在这里插入图片描述

解决方案

在这里插入图片描述

我们只需要CharacterBody2D给我们的位置更改即可,而在Godot中,Position都是相对父节点的位置。所以每次Character移动的时候,我们将CharacterBody2D的位置获取,然后我们将Character的相对位置 设置为0即可

修改代码
public override void Process(double delta)
{//给角色一个速度,因为重力是加速度,所以角色的速度会不断的增加。characterBody2D.Velocity += new Vector2(0, godotProjectSettingHelper.Gravity * (float)delta);//让物体以这个速度进行移动characterBody2D.MoveAndSlide();var postion = characterBody2D.Position;characterBody2D.Position = new Vector2(0, 0);this.Sence.Position += postion;}
动画节点的问题,需要重新绑定

主要,如果修改动画节点的位置,会导致绑定出现问题

在这里插入图片描述

为什么我要这么写

因为我们不一定会写横版战斗游戏,横版战斗是有重力的,但是俯视角战斗又没有重力了,或者说不是垂直向下的重力,而是俯视角的效果。比如【以撒的结合】

在这里插入图片描述

动画效果

在Godot中,AnimationPlayer通过【Play】这个函数来播放动画。但是Godot中,Play是通过字符串的形式调用的。为了保证字符串的正确性,我们添加一个Enum枚举类型来对其进行限制

在这里插入图片描述

初始化AnimationPlayer

在这里插入图片描述

//枚举类型,防止拼写错误
public enum AnimationFlame { REST, idel,running }......public override void Ready()
{nlogHelper.Debug($"当前重力值为:{godotProjectSettingHelper.Gravity}");//初始化子节点characterBody2D = this.Sence.GetNode<CharacterBody2D>("CharacterBody2D");animationPlayer = this.Sence.GetNode<AnimationPlayer>("AnimationPlayer");//播放动画animationPlayer.Play(AnimationFlame.idel.ToString());
}

在这里插入图片描述

输入映射

我们输入上下左右,一般都是wasd,但是因为我们可能要做手柄,可能也要做移动端。所以最好设置一个输入映射好一些。

在这里插入图片描述
我的输入是,wsad是上下左右,【j】/【空格】是跳跃

在这里插入图片描述

在这里插入图片描述

获取输入

Godot 输入处理

我们在任意一个节点下面去获取按钮事件


public override void Process(double delta)
{//获取move_left对应按下事件if (Input.IsActionPressed("move_left")){nlogHelper.Debug("move_left 按下");}}

在这里插入图片描述

简单移动

在这里插入图片描述

public const float RUN_SPEED = 200;
.......public override void Process(double delta)
{var velocity = new Vector2();var direction = Input.GetAxis(InputMapEnum.move_left.ToString(), InputMapEnum.move_right.ToString());var y = godotProjectSettingHelper.Gravity * (float)delta;var x = direction * RUN_SPEED;//在C# 中,velocity = characterBody2D.Velocity;//X是最终速度,所以不需要相加velocity.X = x;//给角色一个速度,因为重力是加速度,所以角色的速度会不断的增加。velocity.Y += y;characterBody2D.Velocity = velocity;//让物体以这个速度进行移动characterBody2D.MoveAndSlide();//同步场景根节点位置var postion = characterBody2D.Position;characterBody2D.Position = new Vector2(0, 0);this.Sence.Position += postion;
}

在这里插入图片描述

完善输入和添加动画

using Godot;
using GodotNet_LegendOfPaladin.Utils;
using GodotProgram.Interfaces;
using GodotProgram.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static GodotNet_LegendOfPaladin.Utils.GodotProjectSettingHelper;namespace GodotNet_LegendOfPaladin.SceneModels
{public class PlayerSceneModel : ISceneModel{public const float RUN_SPEED = 200;public const float JUMP_VELOCITY = -300;//枚举类型,防止拼写错误public enum AnimationFlame {  idel, running,jump }#region IOC注入private NlogHelper nlogHelper;private GodotProjectSettingHelper godotProjectSettingHelper;public PlayerSceneModel(NlogHelper nlogHelper, GodotProjectSettingHelper godotProjectSettingHelper){this.nlogHelper = nlogHelper;this.godotProjectSettingHelper = godotProjectSettingHelper;}#endregion#region 子节点获取private CharacterBody2D characterBody2D;private AnimationPlayer animationPlayer;private Sprite2D sprite2D;public override void Ready(){nlogHelper.Debug($"当前重力值为:{godotProjectSettingHelper.Gravity}");//初始化子节点characterBody2D = this.Sence.GetNode<CharacterBody2D>("CharacterBody2D");animationPlayer = this.Sence.GetNode<AnimationPlayer>("AnimationPlayer");sprite2D = this.Sence.GetNode<Sprite2D>("Sprite2D");//播放动画animationPlayer.Play(AnimationFlame.idel.ToString());}#endregionpublic override void Process(double delta){//初始化速度var velocity = new Vector2();//初始化动画节点var animation = AnimationFlame.idel;var direction = Input.GetAxis(InputMapEnum.move_left.ToString(), InputMapEnum.move_right.ToString());var y = godotProjectSettingHelper.Gravity * (float)delta;var x = direction * RUN_SPEED;var isOnFloor = characterBody2D.IsOnFloor();//在C# 中,velocity = characterBody2D.Velocity;//X是最终速度,所以不需要相加velocity.X = x;//给角色一个速度,因为重力是加速度,所以角色的速度会不断的增加。velocity.Y += y;//如果在地上并且按下跳跃,则直接给一个y轴的速度if(isOnFloor && Input.IsActionJustPressed(InputMapEnum.jump.ToString())){velocity.Y = JUMP_VELOCITY;}if (isOnFloor){if (Mathf.IsZeroApprox(direction)){animation = AnimationFlame.idel;}else{animation = AnimationFlame.running;}}else{animation = AnimationFlame.jump;}//方向翻转if (!Mathf.IsZeroApprox(direction)){sprite2D.FlipH = direction < 0;}characterBody2D.Velocity = velocity;//让物体以这个速度进行移动characterBody2D.MoveAndSlide();//同步场景根节点位置var postion = characterBody2D.Position;characterBody2D.Position = new Vector2(0, 0);this.Sence.Position += postion;animationPlayer.Play(animation.ToString());}}
}

在这里插入图片描述

完善跳跃手感

如果玩过超级马里奥或者别的平台跳跃游戏,都知道有一个手感的东西。就是有个跳跃的提前量。我们现在是正好落地的时候按下跳跃才能跳起来,现在我们将跳跃的按钮进行存储,给与一定的缓冲间隔。

/// <summary>
/// 最长跳跃等待时间
/// </summary>
public const int JUMP_WAIT_TIME = 3000;
/// <summary>
/// 初始化的时候让时间往后退一点,防止时间过快
/// </summary>
private DateTime jumpLastTime = DateTime.Now.AddDays(-1);......
public override void Process(double delta)
{......if (Input.IsActionJustPressed(InputMapEnum.jump.ToString())){jumpLastTime = DateTime.Now;}if (isOnFloor){//如果在地上并且按下跳跃,则直接给一个y轴的速度//超时判断if (jumpLastTime.AddMilliseconds(JUMP_WAIT_TIME) > DateTime.Now){//如果刚好触发了跳跃,给个速度,将jumpLastTime推前velocity.Y = JUMP_VELOCITY;jumpLastTime = DateTime.Now.AddDays(-1);}......}......
}

相关文章:

Godot 4 教程《勇者传说》依赖注入 学习笔记(0):环境配置

文章目录 前言相关地址环境配置初始化环境配置文件夹结构代码结构代码运行 资源文件导入像素风格窗口环境设置背景设置,Tileap使用自动TileMap 人物场景动画节点添加站立节点添加移动动画添加 通过依赖注入获取Godot的全局属性项目声明 当前项目逻辑讲解角色下降添加代码位置问…...

强行让Java和Go对比一波[持续更新]

概述 很多Java开发如果想转Golang的话&#xff0c;比较让Java开发蛋疼的第一是语法&#xff0c;第二是一些思想和设计哲学的Gap&#xff0c;所以我这儿强行整理一波Java和Golang的对比&#xff0c;但是由于GO和Java在很多方面都有不同的设计&#xff0c;所以这些对比的项可以更…...

理解七层网络协议

osi体系结构 上三路&#xff08;管数据&#xff09; 应用层 通过http等&#xff0c;把传输的格式&#xff0c;数据打包 处理网络应用。直接为端用户服务&#xff0c;提供各类应用过程的接口和用户接口。例如&#xff1a;HTTP、Tenlent、FTP、SMTP、NFS等。基于TCP的FTP、HTTP…...

网络协议——HTTP协议

目录 ​编辑 一&#xff0c;HTTP协议基本认识 二&#xff0c;认识URL 三&#xff0c;http协议的格式 1&#xff0c;发送格式 2&#xff0c;回应格式 四&#xff0c;服务端代码 五&#xff0c;http报文细节 1&#xff0c;Post与Get方法 2&#xff0c;Content_lenth 3&…...

八股面试——数据库——索引

索引的概念 B树的概念&#xff1a; 索引的作用 聚簇索引与非聚簇索引 聚簇索引就是主键值&#xff0c;在B树上&#xff0c;通过主键大小&#xff08;数据在B树叶子节点按主键顺序排序&#xff09;寻找对应的叶子节点&#xff0c;叶子节点保存的一整条记录。 非聚簇索引&#x…...

【二分查找】Leetcode 二分查找

题目解析 二分查找在数组有序可以使用&#xff0c;也可以在数组无序的时候使用&#xff08;只要数组中的一些规律适用于二分即可&#xff09; 704. 二分查找 算法讲解 当left > right的时候&#xff0c;我们循环结束&#xff0c;但是当left和right缩成一个点的时候&#x…...

Python+Vuecil笔记

Nginx 进入目录: C:\nginx-1.20.2\nginx-1.20.2 start nginx 开始 nginx -s stop 停止 nginx -s quit 退出CSS 通过标签去写css 循环展示数据 JS 点击时执行事件 Django 配置media 在seetings里面修改 STATIC_URL /static/ MEDIA_URL /upload/ MEDIA_ROOT os.pat…...

C语言关于随机数知识点的总结

在C语言中&#xff0c;随机数的生成通常依赖于特定的库函数&#xff0c;最常用的是 <stdlib.h> 头文件中的 rand() 函数。以下是对随机数知识点的总结、举例和分析&#xff1a; 随机数知识点总结 1.随机数种子&#xff1a;rand() 函数生成的随机数是伪随机数&#xff0…...

网络应用层和传输层

网络中有很多协议这些协议的不同导致了分层这一现象&#xff0c;不同层的主要功能不一样。 应用层&#xff1a;应用程序。数据具体如何使用 传输层&#xff1a;关注起点和终点 网络层&#xff1a;关注路径规划 数据链路层&#xff1a;关注相邻节点的转发 物理层&#xff1…...

Vue3:优化-从响应式数据中获取纯数据

一、情景说明 我们知道&#xff0c;Vue3中&#xff0c;创建变量时&#xff0c;常用ref、reactive来包裹&#xff0c;这样&#xff0c;这个变量就是响应式数据 然而&#xff0c;有时候&#xff0c;我们只需要纯数据 例如&#xff0c;我们在调用后端接口的时候&#xff0c;我们只…...

C#.手术麻醉系统源码 手麻系统如何与医院信息系统进行集成?

C#.手术麻醉系统源码 手麻系统如何与医院信息系统进行集成&#xff1f; 手术麻醉系统与医院信息系统的集成是一个关键步骤&#xff0c;它有助于实现信息的共享和流程的协同&#xff0c;从而提高医疗服务的效率和质量。手麻系统与lis、his、pacs等系统的对接是医院信息化建设的重…...

学习CSS Flexbox 玩flexboxfroggy flexboxfroggy1-24关详解

欢迎来到Flexbox Froggy&#xff0c;这是一个通过编写CSS代码来帮助Froggy和朋友的游戏! justify-content 和 align-items 是两个用于控制 CSS Flexbox 布局的属性。 justify-content&#xff1a;该属性用于控制 Flexbox 容器中子项目在主轴&#xff08;水平方向&#xff09;…...

springboot项目如何配置跨域?

在Spring Boot项目中配置跨域&#xff08;CORS&#xff0c;Cross-Origin Resource Sharing&#xff09;主要是为了允许来自不同源&#xff08;不同的协议、域名或端口&#xff09;的前端应用能够访问后端API。Spring Boot提供了多种方式来配置跨域支持。 1. 使用CrossOrigin注…...

实现第一个动态链接库 游戏插件 成功在主程序中运行 dll 中定义的类

devc 5.11编译环境 dll编译环境设置参考 Dev c C语言实现第一个 dll 动态链接库 创建与调用-CSDN博客 插件 DLL代码和主程序代码如下 注意 dll 代码中的class 类名需要 和主程序 相同 其中使用了函数指针和强制类型转换 函数指针教程参考 以动态库链接库 .dll 探索结构体…...

算法第三十九天-验证二叉树的前序序列化

验证二叉树的前序序列化 题目要求 解题思路 方法一&#xff1a;栈 栈的思路是「自底向上」的想法。下面要结合本题是「前序遍历」这个重要特点。 我们知道「前序遍历」是按照「根节点-左子树-右子树」的顺序遍历的&#xff0c;只有当根节点的所有左子树遍历完成之后&#xf…...

Rust---复合数据类型之字符串与切片(2)

目录 字符串操作删除 (Delete)连接 (Concatenate)字符串转义前情回顾: Rust—复合数据类型之字符串(1) 字符串操作 删除 (Delete) 删除方法仅适用于 String 类型,分别是: pop(),remove(),truncate(),clear(),此外还有drain() 方法。 pop 方法:pop() 方法返回一个 O…...

iOS 应用内网络请求设置代理

主要通过URLSessionConfiguration 的connectionProxyDictionary 属性 为了方便其他同学使用&#xff0c;我们可以通过界面来进行设定&#xff08;是否开启代理、服务端、端口&#xff09;&#xff0c;从而达到类似系统上的设定 具体链接参考&#xff1a;为 iOS 网络请求设置代理…...

什么是MariaDB

2024年4月6日&#xff0c;周六晚上 今晚在Debian12上安装mysql时&#xff0c;运行后却发现是MariaDB MariaDB是一个开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是MySQL的一个分支和替代品。MariaDB由MySQL的原始开发者之一Michael "Monty&qu…...

【面试八股总结】传输控制协议TCP(三)

参考资料 &#xff1a;小林Coding、阿秀、代码随想录 一、TCP拥塞控制⭐ 1. 慢启动 – Slow Start 慢启动是指TCP连接刚建立&#xff0c;一点一点地提速&#xff0c;试探一下网络的承受能力&#xff0c;以免直接扰乱了网络通道的秩序。 慢启动算法&#xff1a; 初始拥塞窗口…...

今年过去了多少天?(switch)

//今年已经过去了几天&#xff1f; #include <stdio.h> int monthday(int year,int month){switch(month){case 1:return 31;case 2:if ((year % 4 0 && year % 100 ! 0)||year % 400 0){return 29;}else{return 28;}break;case 3:return 31;case 4:return 30;…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

实战设计模式之模板方法模式

概述 模板方法模式定义了一个操作中的算法骨架&#xff0c;并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下&#xff0c;重新定义算法中的某些步骤。简单来说&#xff0c;就是在一个方法中定义了要执行的步骤顺序或算法框架&#xff0c;但允许子类…...