UnityAI——个体AI角色的操控行为脚本
注:本文用到了前文所用的基类UnityAI——操控行为编程的主要基类-CSDN博客
在一些游戏中,可能会遇到想让AI角色追逐或者避开玩家的情况。
如在飞机模拟游戏中,让导弹跟踪和进攻玩家或玩家的飞行器。这种情况下,可以运用本节介绍的技术。
一、靠近
操控行为中的靠近是指,指定一个目标位置,根据当前的运动速度向量,返回一个操控AI角色到达该目标位置的"操控力",使AI角色自动向该位置移动。
要想让AI角色靠近目标,首先要计算出AI角色在理想情况下到达目标位置的预期速度。该预期速度可看作是从AI角色的当前位置到目标位置的向量。操控向量是预期速度与AI角色当前速度的差,该向量大小随着当前位置的变化而变化,从而形成角色的寻找路径。
由于操控行为是基于力和速度的,速度不会突变,因此,如果角色一直采取靠近行为,那么最终它将会从目标穿过,然后再重新接近目标,如此往复。
当然,如果目标物体包含一个碰撞体,那么,接下来的行为就要由Character Controller决定了。如果不希望出现这种情况,可以采用后面介绍的Arrive行为,也可以另外添加一些处理步骤。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SteeringForSeek : Steering
{public GameObject target;private Vector3 desiredVelocity;//预期速度private Vehicle m_vehicle;//获得被操控的AI角色private float maxSpeed;private bool isPlanar;void Start(){m_vehicle = GetComponent<Vehicle>();maxSpeed = m_vehicle.maxSpeed;isPlanar = m_vehicle.isPlanar; }public override Vector3 Force(){desiredVelocity = (target.transform.position - transform.position).normalized * maxSpeed;if (isPlanar)desiredVelocity.y = 0;return (desiredVelocity - m_vehicle.velocity);}}
二、离开
离开和靠近行为正好相反,它会产生一个操控AI角色离开目标的力,而不是靠近目标的力。它们之间唯一的区别是DeisredVelocity具有相反的方向。
接着,还可以进一步调整,只有当AI角色进入目标周围一定范围内时,才产生离开的力,这样可以模拟出AI角色的有限感知范围
这里采用了Vector3.Distance函数来计算当前位置与目标位置之间的距离。事实上,如果采用Vector3.sqrMagnitude函数,将会得到更快的计算速度,因为省去了计算平方根的时间,这时可以预先计算fearDistance的平方并存储到一个变量中。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SteeringForFlee : Steering
{public GameObject target;public float fearDistance = 20;private Vector3 desiredVelocity;//预期速度private Vehicle m_vehicle;//获得被操控的AI角色private float maxSpeed;void Start(){m_vehicle = GetComponent<Vehicle>();maxSpeed = m_vehicle.maxSpeed;}public override Vector3 Force(){Vector3 temPos = new Vector3(transform.position.x, 0, transform.position.z);Vector3 temTargetPos = new Vector3(target.transform.position.x, 0, target.transform.position.z);if (Vector3.Distance(temPos, temTargetPos) > fearDistance)return new Vector3(0, 0, 0);desiredVelocity = (transform.position - target.transform.position).normalized * maxSpeed;return (desiredVelocity-m_vehicle.velocity);}
}
三、抵达
有时我们希望AI角色能够减速并停到目标位置,避免冲过目标,例如,车辆在接近十字路口时逐渐减速,然后停在路口处,这时就需要用到抵达行为。
在角色距离目标较远时,抵达与靠近行为的状态是一样的,但是接近目标时,不再是全速向目标移动,而代之以使AI角色减速,知道最终恰好停在目标位置。何时开始减速是通过参数进行设置的,这个参数可以看成是停止半径。当角色在停止半径之外时,以最大速度移动;当角色在停止半径之内时,逐渐减小预期速度,直到减小为0.这个参数的设置很关键,它决定了抵达行为的最终效果。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SteeringForArrive : Steering
{public bool isPlanar = true;public float arrivalDistance = 0.3f;public float characterRadius = 1.2f;public float slowDownDistance;public GameObject target;private Vector3 desiredVelocity;//预期速度private Vehicle m_vehicle;//获得被操控的AI角色private float maxSpeed;void Start(){m_vehicle = GetComponent<Vehicle>();maxSpeed = m_vehicle.maxSpeed;isPlanar = m_vehicle.isPlanar;}public override Vector3 Force(){Vector3 toTarget = target.transform.position - transform.position;Vector3 desiredVelocity;Vector3 returnForce;if (isPlanar)toTarget.y = 0;float distance = toTarget.magnitude;if (distance > slowDownDistance){desiredVelocity = toTarget.normalized * maxSpeed;returnForce = desiredVelocity - m_vehicle.velocity;}else{desiredVelocity = toTarget - m_vehicle.velocity;returnForce = desiredVelocity - m_vehicle.velocity;}return returnForce;}void OnDrawGizmos(){Gizmos.DrawWireSphere(target.transform.position, slowDownDistance);}
}
四、追逐
追逐行为与靠近行为很相似,只不过目标不再是静止不动,而是另一个可移动的角色。最简单的追逃方式是直接向目标的当前位置靠近,不过这样看上去很不真实。举例来说,众所周知,当动物追猎物时,不是直接向猎物当前的位置奔跑,而是要预判,朝着其未来位置的方向追去,这样才能在最短时间内追上猎物。在AI中,把这种操控行为称为"追逐"。
如何实现这种智能的追逐行为呢?我们可以使用一个简单的预测器,在每一帧重新计算它的值。
假设采用一个线性预测器,有假设在预测时间间隔T时间内角色不会转向,角色经过时间T后的未来位置可以用当前速度乘以T来确定,然后把得到的值加到角色当前位置上,就得到未来位置了。最后,再以预测位置作为目标,应用靠近行为就可以了。
实现追逐行为的一个关键是如何确定T。可以把它设置为一个常数,也可以当追逐者距离目标较远时设为较大的值,而接近目标时设为较小的值。
这里,设定预测时间和追逐者与逃避者之间的距离成正比,与二者的速度成正比。
一些情况下,追逐可能会提前结束。例如:逃避者在前面,几乎面对追逐者,那么追逐者应该直接向逃避者的当前位置移动。二者之间的关系可以通过计算逃避者朝向向量与AI角色朝向向量的点积得到,在下面的代码中,逃避者朝向的反向和AI角色的朝向必须大约在20度范围之内,才可以被认为是面对着的。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SteeringForPersuit : Steering
{public GameObject target;private Vector3 desiredVelocity;//预期速度private Vehicle m_vehicle;//获得被操控的AI角色private float maxSpeed;void Start(){m_vehicle = GetComponent<Vehicle>();maxSpeed = m_vehicle.maxSpeed;}public override Vector3 Force(){Vector3 toTarget = target.transform.position - transform.position;float relativeDirection = Vector3.Dot(transform.forward, target.transform.forward);//计算追逐者的前方与逃避者前方之间的夹角if (Vector3.Dot(toTarget, transform.forward) > 0 && relativeDirection < -0.95f)//夹角大于0且追逐者基本面对着逃避者{desiredVelocity=(target.transform.position - transform.position).normalized*maxSpeed;return (desiredVelocity - m_vehicle.velocity); }float lookaheadTime = toTarget.magnitude / (maxSpeed + target.GetComponent<Vehicle>().velocity.magnitude);//计算预测时间,正比于距离,反比于速度和desiredVelocity = (target.transform.position + target.GetComponent<Vehicle>().velocity * lookaheadTime - transform.position).normalized * maxSpeed;return(desiredVelocity - m_vehicle.velocity);}
}
五、逃避
逃避行为与追逐行为的不同是它试图使AI角色逃离预测位置。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SteeringForEvade :Steering
{public GameObject target;private Vector3 desiredVelocity;//预期速度private Vehicle m_vehicle;//获得被操控的AI角色private float maxSpeed;void Start(){m_vehicle = GetComponent<Vehicle>();maxSpeed = m_vehicle.maxSpeed;}public override Vector3 Force(){Vector3 toTarget = target.transform.position - transform.position;float lookaheadTime = toTarget.magnitude / (maxSpeed + target.GetComponent<Vehicle>().velocity.magnitude);//向前预测的时间desiredVelocity = (transform.position - (target.transform.position+target.GetComponent<Vehicle>().velocity*lookaheadTime)).normalized * maxSpeed;return (desiredVelocity - m_vehicle.velocity);}
}
六、随机徘徊
很多时候,我们需要让游戏中的角色随机移动,比如说士兵的巡逻。我们希望这种随机移动看上去是真实的,而不是一直循环某个路径。
利用操控行为来实现随机派啊坏有多种不同的方法,最简单的方式是利用前面提到的靠近行为。在场景中随机放置目标,让角色靠近目标,每隔一定时间就随机改变目标的位置。这个方法很简单,但缺点也很明显,比如角色可能会突然掉头,因为目标可能移动到了角色的后面。
解决这个问题的原理与内燃机的气缸曲轴转动相似。在角色(气缸)通过连杆连接到曲轴上,目标被限定到曲轴圆周上,移向目标。为了看得更随机,每帧给目标附加一个随机的位移。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SteeringForWander : Steering
{public float wanderRadius; //徘徊半径public float wanderDistance; //徘徊距离public float wanderJitter; //每秒加到目标的随即位移的最大值public bool isPlanar;private Vector3 desiredVelocity;//预期速度private Vehicle m_vehicle;//获得被操控的AI角色private float maxSpeed;private Vector3 circleTarget;private Vector3 wanderTarget;void Start(){m_vehicle = GetComponent<Vehicle>();maxSpeed = m_vehicle.maxSpeed;isPlanar = m_vehicle.isPlanar;circleTarget = new Vector3(wanderRadius * 0.707f, 0, wanderRadius * 0.707f); //选取与安全上的一个点作为初始点}public override Vector3 Force(){Vector3 randomDisplacement = new Vector3((Random.value - 0.5f) * 2 * wanderJitter, (Random.value - 0.5f) * 2 * wanderJitter, (Random.value - 0.5f) * 2 * wanderJitter);if (isPlanar)randomDisplacement.y = 0;circleTarget+=randomDisplacement;//将随机位移加到初始点上circleTarget = wanderRadius * circleTarget.normalized;//由于新位置很可能不在圆周上,因此需要投影到圆周上wanderTarget = m_vehicle.velocity.normalized * wanderDistance + circleTarget + transform.position;//之前计算出的值是相对于AI的,需要转换为世界坐标desiredVelocity = (wanderTarget - transform.position).normalized * maxSpeed;return (desiredVelocity - m_vehicle.velocity);}
}
七、路径跟随
就像赛道上的赛车需要导航一样,路径跟随会产生一个操控力,使AI角色沿着由事先设置的轨迹构成路径的一系列路点移动。
最简单的方式是将当前路点设置为路点列表中的第一个路点,用靠近行为来靠近这个路点,至非常接近这个点;然后靠近列表中的下一个路点,一直到最后一个路点。
在实现这一功能时,需要设置一个"路点半径"参数,这个参数的设置会引起路径形状的变化
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SteeringFollowPath : Steering
{public GameObject[] waypoints = new GameObject[4];//由节点表示的路径private Transform target;private int currentNode;private float arriveDistance;private float sqrArriveDistacne;private int numberOfNodes;private Vector3 force;private Vector3 desiredVelocity;//预期速度private Vehicle m_vehicle;//获得被操控的AI角色private float maxSpeed;private bool isPlanar;public float slowDownDistacne;void Start(){numberOfNodes = waypoints.Length;m_vehicle = GetComponent<Vehicle>();maxSpeed = m_vehicle.maxSpeed;isPlanar = m_vehicle.isPlanar;currentNode = 0;target = waypoints[currentNode].transform;arriveDistance = 1.0f;sqrArriveDistacne = arriveDistance * arriveDistance;}public override Vector3 Force(){force = new Vector3(0, 0, 0);Vector3 dist = target.position - transform.position;if (isPlanar)dist.y = 0;if(currentNode==numberOfNodes-1){if(dist.magnitude>slowDownDistacne){desiredVelocity=dist.normalized*maxSpeed;force=desiredVelocity-m_vehicle.velocity;}else{desiredVelocity = dist - m_vehicle.velocity;force = desiredVelocity - m_vehicle.velocity;}}else{if(dist.sqrMagnitude<sqrArriveDistacne){currentNode++;target = waypoints[currentNode].transform;}desiredVelocity= dist.normalized * maxSpeed;force = desiredVelocity - m_vehicle.velocity;}return force;}
}
八、避开障碍
避开障碍是指操控AI角色避开路上的障碍物,例如在路径上有一颗树,当角色距离树比较近时,就会产生一个"排斥力",使AI角色不至于撞上树。当有好几棵树时,至产生躲避最近的树的操控力,这样,AI角色就会一个一个地躲开这些树。
在这个算法中,首先需要发现障碍物。AI角色唯一需要担心的就是挡在其路线前方的那些物体。算法的分析步骤如下:
1、用角色前进的速度生成一个向亮ahead
ahead=position+normalize(velocity)*MAX_SEE_AHEAD。ahead的长度决定了AI能看到的距离
2、每个障碍物都用一个几何形状表示,这里采用包围球来标识场景中的每个障碍。
一种可能的方法是检测ahead向量与障碍物的包围球是否相交。这里采用简化的方法。
需要一个向量ahead2,ahead2=ahead*0.5
3、接下来进行碰撞检测。只需要比较向量的终点与球心的距离d是否小于球的半径。如果ahead与ahead2中的一个向量在球内,那么说明障碍物在前方。如果监测到了多个障碍物,那么选择最近的那个。
4、计算操控力
avoidance_force=ahead-obstacle_center
avoidance_force=normalize(avoidance_force)*MAX_AVOID_FORCE
采用这种方法的缺点是,当AI角色接近障碍而操控力正在使其原理的时候,即使AI正在旋转,也可能会检测到碰撞。一种改进方法是根据AI角色的当前速度调整ahead向量,计算方法如下:
Dynamic_length=length(velocity)/MAX_VELOCITY
ahead=position+normalize(velocity)*dynamic_length
这时,dynamic_length的范围是0~1,当全速移动时,值是1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SteeringForCollisionAvoidance :Steering
{public bool isPlanar;private Vector3 force;private Vector3 desiredVelocity;//Ԥ���ٶ�private Vehicle m_vehicle;//��ñ��ٿص�AI��ɫprivate float maxSpeed;private float maxForce;public float avoidanceForce;public float MAX_SEE_AHEAD = 2.0f;//�ܼ���������private GameObject[] allColliders;void Start(){m_vehicle = GetComponent<Vehicle>();maxSpeed = m_vehicle.maxSpeed;isPlanar = m_vehicle.isPlanar;maxForce = m_vehicle.maxForce;if(avoidanceForce>maxForce)avoidanceForce = maxForce;allColliders = GameObject.FindGameObjectsWithTag("obstacle");//�洢TagΪobstacle��������Ϊ��ײ��}public override Vector3 Force(){RaycastHit hit;Vector3 force = new Vector3(0, 0, 0);Vector3 velocity = m_vehicle.velocity;Vector3 normalizedVelocity = velocity.normalized;Debug.DrawLine(transform.position, transform.position + normalizedVelocity * MAX_SEE_AHEAD * (velocity.magnitude / maxSpeed));//����һ�����ߣ���Ҫ���������������ཻ����ײ��if (Physics.Raycast(transform.position, normalizedVelocity, out hit, MAX_SEE_AHEAD * velocity.magnitude / maxSpeed)){Vector3 ahead = transform.position + normalizedVelocity * MAX_SEE_AHEAD * (velocity.magnitude / maxSpeed); //���������ij����ײ���ཻ����ʾ������ײforce=ahead-hit.collider.transform.position;//���������ײ����IJٿ���force *= avoidanceForce;if (isPlanar)force.y = 0;foreach(GameObject c in allColliders)//�ı���ײ�����ɫ{if (hit.collider.gameObject == c){c.GetComponent<Renderer>().material.color = Color.black;}elsec.GetComponent<Renderer>().material.color = Color.white;}}else//���ǰ��û�м���ײ�壬��������ײ��ı���ɫ{foreach (GameObject c in allColliders){c.GetComponent<Renderer>().material.color = Color.white;}}return force;}
}
相关文章:

UnityAI——个体AI角色的操控行为脚本
注:本文用到了前文所用的基类UnityAI——操控行为编程的主要基类-CSDN博客 在一些游戏中,可能会遇到想让AI角色追逐或者避开玩家的情况。 如在飞机模拟游戏中,让导弹跟踪和进攻玩家或玩家的飞行器。这种情况下,可以运用本节介绍…...

ssh登录界面变成vim提示,进不去系统
是ubuntu系统 使用远程连接root,进去后发现界面变成vim编辑器的介绍界面了 使用普通用户登录 查询用户的登录shell是不是有问题 sudo vim /etc/passwd 发现用户shell变成了vim编辑器 修改为/bin/bash就可以正常登录了 重新登录测试就正常了...

虹科示波器 | 汽车免拆检修 | 2012 款上汽大众帕萨特车 发动机偶尔无法起动
一、故障现象 一辆2012款上汽大众帕萨特车,搭载CFB发动机,累计行驶里程约为12万km。车主反映,将点火开关置于起动挡,偶尔只能听到“咔哒”一声,起动机没有反应,类似蓄电池亏电时起动发动机的现象。为此&…...

UE5.0.3版本 像素流送 Pixel Streaming
目录 0 引言1 准备工作1.1 下载Node.js1.2 下载 PixelStreaming(非必须) 2 快速入门2.1 打包工程2.2 启动信令服务器2.3 启动工程2.4 打开网页 3 总结 🙋♂️ 作者:海码007📜 专栏:UE虚幻引擎专栏&#x…...

BetterDisplay Pro v1.4.15(显示器管理管理软件)
BetterDisplay Pro是一款屏幕显示优化工具,可用于Windows和Mac操作系统。它可以帮助用户调整屏幕的亮度、对比度、色彩等参数,以获得更好的视觉体验。此外,BetterDisplay Pro还提供了一些额外的功能,如屏幕分割、窗口管理、快捷键…...

蓝桥等考C++组别四级006
第一部分:选择题 1、C L4 (20分) 以下选项中,不是逻辑运算符的选项是( )。 A.! B.|| C.&& D.< 正确答案:D 2、C L4 (20分) …...

app开发之后需要做什么
在完成app的开发之后,还有一系列的工作需要进行,以确保app的顺利上线和用户的良好体验。下面将从原理和详细介绍两个方面来介绍app开发之后需要做的工作。 一、原理介绍 1. 测试与调试:在app开发完成后,需要进行全面的测试与调试…...

某汽车金融企业:搭建SDLC安全体系,打造智慧金融服务样本
某汽车金融企业是国内头部汽车金融公司,已经为超过数百万名客户提供专业的汽车金融服务。该公司通过近几年的数字化创新,在提升客户体验、提高管理效率、降低经营成本等方面已具备很强的服务能力,让客户获得更方便、更快捷、更灵活的金融服务…...

iOS GCD(Grand Central Dispatch)
iOS 常用有三种线程管理方式,分别是 NSThread、GCD 与 NSOperation,现在我们先来了解一下其中的 GCD 串行与并行针对的是任务队列,而同步与异步,针对的则是线程。 Serial Queue Sync 序列执行同步 Serial Queue Async 序列执…...

Cross-Entropy Loss(多分类损失函数)
文章目录 1. 网络输出output:score2. Cross-Entropy Loss(多分类损失函数) 1. 网络输出output:score 2. Cross-Entropy Loss(多分类损失函数) 先用softmax function把score 变成 probabilities。再用交叉熵损失函数来进行Loss的计算...

TP858 3BSE018138R1 具有高性能CPU的工业PC技术
TP858 3BSE018138R1 具有高性能CPU的工业PC技术 为了充分利用新电脑的扩展图形功能,如DirectX,Beckhoff Automation重新设计了TwinCAT automation软件套件中的Scope工具。这为TwinCAT用户在灵活的软件环境中提供了一系列令人印象深刻的测量技术。改进的…...

Observability:使用 OpenTelemetry 手动检测 .NET 应用程序
作者:David Hope 在快节奏的软件开发领域,尤其是在云原生领域,DevOps 和 SRE 团队日益成为应用程序稳定性和增长的重要合作伙伴。 DevOps 工程师不断优化软件交付,而 SRE 团队则充当应用程序可靠性、可扩展性和顶级性能的管理者。…...

生产事故:redis主从的坑
一、问题 昨天生产redis缩容,3主3从模式,重启了服务器,重启了redis; 结果今天发现生产服务报错了,连接不上redis。 排查发现,由于生产后台只配置了一个redis的ip,本来是主redis的ip的&#x…...

maven本地仓库有依赖包,还会远程下载的问题
maven本地仓库有依赖包,还会远程下载的问题 传送门...

动作捕捉系统处理单点多点丢点问题
在动作捕捉数据采集过程中,丢点是经常容易遇到的问题。NOKOV度量动作捕捉软件可以方便地解决丢点问题。 一、单点丢点的处理 如下图,已经采集了动捕数据。 查看是否有丢点,在形影软件左上角选择“窗口分割”,在下方分割出一个空…...

FIFO 位宽转换
从8位转32位 module tb_fifo();reg clk,rst; initial beginclk0;forever #4.545 clk~clk; end initial beginrst1;#9.09 rst0; endreg [31:0] cnts; always (posedge clk or posedge rst) beginif(rst)begincnts < 32d0;endelsebegincnts < cnts 1b1;end endreg […...

瑞明达:聚“追梦”之力,共圆“经济梦”
矢志不渝,笃行不怠,争当“一心一意同国行”的无悔“追梦人”。过往几年,国际形势风高浪急,国内环境复杂多变,在后疫情时代、经济恢复压力等多种超预期的因素冲击下,瑞明达团队全面贯彻落实国家发展政策&…...

UE5数字孪生制作(一) - QGIS 学习笔记
1.下载 QGIS是免费的GIS工具,下载地址: https://www.qgis.org/en/site/ 2.安装 - 转中文 按照步骤安装,完成后,在菜单 设置settings里,选择options,修改语言 确定后,需要重启下软件 3.学习视…...

STM32 使用HAL库,HAL_Delay()会卡死, 程序一直卡在 HAL_GetTick( ) 函数中(已解决)
今天遇到个很奇怪的问题, 不知道为什么, 单片机运行一会之后, 系统就没反应了, 经过调试发现, 系统卡在HAL_Delay()中了. 之前也遇到过这个问题后来把HAL_Delay 去掉了. 然后发现不行, 还是得有它.不然发串口数据发的太快会乱掉. 得慢点发. 然后调试到HAL_Delay()方法的内部发…...

Maven Repository使用
1.Maven Repository网站 https://mvnrepository.com/https://mvnrepository.com/ 2.查询需要的依赖 3.参考例子 <!-- https://mvnrepository.com/artifact/org.freeswitch.esl.client/org.freeswitch.esl.client --> <dependency> <groupId>org.freesw…...

智安网络|保护您的应用程序免受攻击:重要的安全强化措施
在今天的数字化时代,应用程序安全成为了企业和个人必须重视的重要领域。应用程序普遍存在的安全漏洞成为黑客们进行攻击的一个突破口。为了保护敏感数据和个人隐私,我们必须了解并实施一系列的关键措施来加固应用程序的安全性。 首先,一个关…...

python3.8 use async getting invalid sysntax
python3.8 use async getting invalid sysntax 加载fever-drqa时报错: File "/data/yangjun/fact/wikifact/scripts/search_module.py", line 2, in <module> from drq…...

Mac 解决 APP 快捷键冲突
打开 Mac 系统设置键盘->键盘快捷键->App快捷键->添加快捷键(加号)->标题需要和tab名称完全一致(包括中英文、标点符号等,如下图)设置快捷键即可 Reference: https://www.cnblogs.com/Questio…...

mysql之事务
(一)事务 1、事务是一种机制一个操作序列,包含了一组数据库的操作命令,所有命令都是一个整体,向系统提交或者撤销的操作,要么都执行,要么都不执行 2、不可分割的单位 (二…...

组件化npm包打包和使用
背景:本地环境对功能组件提取,开发环境下通过本地路径引用,发布模式下走npm包引用 1、项目下新建packages/HelloWorld文件夹,在此文件夹下运行终端 npm init 新建packages/HelloWorld/index.vue文件 新建packages/HelloWorld/ind…...

Windows 内置Linux子系统的配置(From WSL1 to WSL2)
目录 我是如何从WSL1转到WSL2的? WSL1与WSL2的功能区别: 配置下载源 SSH配置 优雅使用windows的Linux子系统 我是如何从WSL1转到WSL2的? 第一次安装的子系统是WSL1的,因为不能使用systemctl ,以及因为WSL1没有完整的Linux内核,所以使得WSL1很多命令…...

2023-11-03 android app TextView 滚动,ScrollView 之外的另外一种方法
一、布局xml文件中TextView 增加下面属性 android:maxLines "AN_INTEGER" android:scrollbars "vertical" 二、在java代码中添加下面代码,就可以滚动了。 m_TextView.setMovementMethod(new ScrollingMovementMethod())...

SAP 获取GOS附件清单及URL数据方法
很久没有更新了,断更了快两个月了,最近准备软考考试,刚考完不知道这次能不能通过 回归正题 SAP中很多业务中都是可以上传附件或者是上传URL的路径的,上传附件长时间会占用SAP的空间,使用GOS大多数都是采用上传URL的方式…...

VUE批量下载图片打包成zip下载
import JSZip from jszip; import { saveAs } from file-saver; downloadImages() {var zip new JSZip();// 创建images文件夹//imageUrls[本地路径,或者网络路径];var imgFolder zip.folder("images");let flag 0 // 判断加载了几张图片的标识for (let i 0; i …...

微信小程序-form表单-获取用户输入文本框的值
微信小程序-form表单-获取用户输入文本框的值 data: {userName: ,userPwd:""},//获取用户输入的用户名 userNameInput:function(e) {this.setData({userName: e.detail.value}) }, passWdInput:function(e) {this.setData({userPwd: e.detail.value}) }, //获取用户输…...