[Unity Demo]从零开始制作空洞骑士Hollow Knight第五集:再制作更多的敌人
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、制作敌人另个爬虫Crawler
- 1.公式化导入制作另个爬虫Crawler素材
- 2.制作另个爬虫Crawler的Crawler.cs状态机
- 3.制作敌人另个爬虫Crawler的playmaker状态机
- 二、制作敌人飞虫Fly
- 1.公式化导入制作飞虫Fly素材
- 2.制作敌人飞虫Fly的playmaker状态机
- 总结
前言
如标题所示,最近感觉有些没活了,或者说是趁热打铁再制作更多的敌人,于是本期的主角就决定是两个大家刚进入空洞骑士就经常看到的敌人另一个爬虫Crawler和飞虫Fly。
一、制作敌人另一个爬虫Crawler
1.公式化导入制作另个爬虫Crawler素材
首先我们先完成Crawler的完整行为,第一步导入素材,分别为它制作tk2dspritecollection和tk2dspriteanimation,
然后就到了公式化设置一个敌人的时候了Rb2d , audiosource, boxcollider2d:
可以看到它不需要其它的子物体,因为只需要执行行走,死亡,转向的状态。
2.制作另一个爬虫Crawler的Crawler.cs状态机
创建同名函数给该游戏对象
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Crawler : MonoBehaviour
{public float speed;[Space]private Transform wallCheck; //墙面检测的位置private Transform groundCheck; //地面检测的位置private Vector2 velocity; //记录速度private CrawlerType type;private Rigidbody2D body;private tk2dSpriteAnimator anim;private void Awake(){body = GetComponent<Rigidbody2D>();anim = GetComponent<tk2dSpriteAnimator>();}private void Start(){float z = transform.eulerAngles.z;//通过transform.eulerAngles.z来判断哪种类型的Crawlerif (z >= 45f && z <= 135f){type = CrawlerType.Wall;velocity = new Vector2(0f, Mathf.Sign(-transform.localScale.x) * speed);}else if (z >= 135f && z <= 225f){type = ((transform.localScale.y > 0f) ? CrawlerType.Roof : CrawlerType.Floor);velocity = new Vector2(Mathf.Sign(transform.localScale.x) * speed, 0f);}else if (z >= 225f && z <= 315f){type = CrawlerType.Wall;velocity = new Vector2(0f, Mathf.Sign(transform.localScale.x) * speed);}else{type = ((transform.localScale.y > 0f) ? CrawlerType.Floor : CrawlerType.Roof);velocity = new Vector2(Mathf.Sign(-transform.localScale.x) * speed, 0f);}//TODO:CrawlerType crawlerType = type;if(crawlerType != CrawlerType.Floor){if(crawlerType - CrawlerType.Roof <= 1){body.gravityScale = 0;//如果在墙面面上rb2d的重力就设置为1}}else{body.gravityScale = 1; //如果在地面上rb2d的重力就设置为1//TODO:}StartCoroutine(Walk());}/// <summary>/// 使用协程实现Walk函数,循环直至hit=true后挂起然后启用协程Turn()/// </summary>/// <returns></returns>private IEnumerator Walk(){for(; ; ){anim.Play("Walk");body.velocity = velocity;bool hit = false;while (!hit){if(CheckRayLocal(wallCheck.localPosition,transform.localScale.x > 0f ? Vector2.left : Vector2.right, 1f)){hit = true;break;}if (!CheckRayLocal(groundCheck.localPosition, transform.localScale.y > 0f ? Vector2.down : Vector2.up, 1f)){hit = true;break;}yield return null;}yield return StartCoroutine(Turn());yield return null;}}/// <summary>/// 使用协程实现转向函数/// </summary>/// <returns></returns>private IEnumerator Turn(){body.velocity = Vector2.zero;yield return StartCoroutine(anim.PlayAnimWait("Turn"));transform.SetScaleX(transform.localScale.x * -1f);velocity.x = velocity.x * -1f;velocity.y = velocity.y * -1f;}/// <summary>/// 发射射线,检测是否有LayerMask.GetMask("Terrain").collider/// </summary>/// <param name="originLocal"></param>/// <param name="directionLocal"></param>/// <param name="length"></param>/// <returns></returns>public bool CheckRayLocal(Vector3 originLocal, Vector2 directionLocal, float length){Vector2 vector = transform.TransformPoint(originLocal);Vector2 vector2 = transform.TransformDirection(directionLocal);RaycastHit2D raycastHit2D = Physics2D.Raycast(vector, vector2, length, LayerMask.GetMask("Terrain"));Debug.DrawLine(vector, vector + vector2 * length);return raycastHit2D.collider != null;}private enum CrawlerType{Floor,Roof,Wall}
}
回到Unity编辑器中,如果你的是开始往左走的话,记得设置speed为负数
只需要这个就行了。我们不需要挂载Lineofsightdetector.cs,这个就是敌人发现敌人到自己攻击范围的脚本
3.制作敌人另个爬虫Crawler的playmaker状态机
创建一个名字叫Crawler的playmaker状态机:
变量和事件如下所示:
同样我们还需要自定义脚本:
using System.Collections;
using UnityEngine;namespace HutongGames.PlayMaker.Actions
{[ActionCategory("Enemy AI")]public class WalkLeftRight : FsmStateAction{private Rigidbody2D body;private tk2dSpriteAnimator spriteAnimator;private Collider2D collider;public FsmOwnerDefault gameObject;public float walkSpeed; //移动速度public bool spriteFacesLeft; //sprite开始时是向左的吗public string groundLayer; //也就是Terrainpublic float turnDelay; //转向延时private float nextTurnTime; //下一次转身的时间[Header("Animation")]public FsmString walkAnimName; //walk的动画名字public FsmString turnAnimName; //turn的动画名字public FsmBool startLeft;public FsmBool startRight;public FsmBool keepDirection;private float scaleX_pos;private float scaleX_neg;private const float wallRayHeight = 0.5f; //检测墙壁的射线高度private const float wallRayLength = 0.1f; //检测墙壁的射线长度private const float groundRayLength = 1f; //检测地面的射线高度private GameObject target; //目标private Coroutine walkRoutine; //walk的协程private Coroutine turnRoutine; //turn的协程private bool shouldTurn; //应该转身了吗private float Direction{get{if (target){return Mathf.Sign(target.transform.localScale.x) * (spriteFacesLeft ? -1 : 1); //记录方向属性}return 0f;}}public override void OnEnter(){UpdateIfTargetChanged();SetupStartingDirection();walkRoutine = StartCoroutine(Walk());}/// <summary>/// 退出时停掉所有正在执行的协程/// </summary>public override void OnExit(){if(walkRoutine != null){StopCoroutine(walkRoutine);walkRoutine = null;}if (turnRoutine != null){StopCoroutine(turnRoutine);turnRoutine = null;}}/// <summary>/// 如果目标target发生变化后重新初始化/// </summary>private void UpdateIfTargetChanged(){GameObject ownerDefaultTarget = Fsm.GetOwnerDefaultTarget(gameObject);if(ownerDefaultTarget != target){target = ownerDefaultTarget;body = target.GetComponent<Rigidbody2D>();collider = target.GetComponent<Collider2D>();spriteAnimator = target.GetComponent<tk2dSpriteAnimator>();}}private IEnumerator Walk(){if (spriteAnimator){spriteAnimator.Play(walkAnimName.Value);}for(; ; ){if (body){Vector2 velocity = body.velocity;velocity.x = walkSpeed * Direction;body.velocity = velocity;if(shouldTurn || (CheckIsGrounded() && (CheckWall() || CheckFloor()) && Time.time >= nextTurnTime)){shouldTurn = false;nextTurnTime = Time.time + turnDelay;turnRoutine = StartCoroutine(Turn());yield return turnRoutine;}}yield return new WaitForFixedUpdate();}}private IEnumerator Turn(){Vector2 velocity = body.velocity;velocity.x = 0f;body.velocity = velocity;tk2dSpriteAnimationClip clipByName = spriteAnimator.GetClipByName(turnAnimName.Name);if(clipByName != null){float seconds = clipByName.frames.Length / clipByName.fps;//计算出动画播放的时间spriteAnimator.Play(clipByName);yield return new WaitForSeconds(seconds);}Vector3 localScale = target.transform.localScale;localScale.x *= -1f;target.transform.localScale = localScale;if (spriteAnimator){spriteAnimator.Play(walkAnimName.Value);}turnRoutine = null;}/// <summary>/// 检测是否接触到墙面/// </summary>/// <returns></returns>private bool CheckWall(){Vector2 vector = collider.bounds.center + new Vector3(0f, -(collider.bounds.size.y / 2f) + wallRayHeight);Vector2 vector2 = Vector2.right * Direction;float num = collider.bounds.center.x / 2f + wallRayLength;Debug.DrawLine(vector, vector + vector2 * num);return Physics2D.Raycast(vector, vector2, num, LayerMask.GetMask(groundLayer)).collider != null;}/// <summary>/// 检测是否接触到地板/// </summary>/// <returns></returns>private bool CheckFloor(){Vector2 vector = collider.bounds.center + new Vector3((collider.bounds.size.x / 2f + wallRayLength) * Direction, -(collider.bounds.size.y / 2f) + wallRayHeight);Debug.DrawLine(vector, vector + Vector2.down * groundRayLength);return !(Physics2D.Raycast(vector, Vector2.down, groundRayLength, LayerMask.GetMask(groundLayer)).collider != null);}/// <summary>/// 检测是否已经接触到地面/// </summary>/// <returns></returns>private bool CheckIsGrounded(){Vector2 vector = collider.bounds.center + new Vector3(0f,-(collider.bounds.center.y / 2f) + wallRayHeight);Debug.DrawLine(vector, vector + Vector2.down * groundRayLength);return Physics2D.Raycast(vector, Vector2.down, groundRayLength, LayerMask.GetMask(groundLayer)).collider != null;}/// <summary>/// 设置开始时GameObject的方向/// </summary>private void SetupStartingDirection(){if (target.transform.localScale.x < 0f){if (!spriteFacesLeft && startRight.Value){shouldTurn = true;}if (spriteFacesLeft && startLeft.Value){shouldTurn = true;}}else{if (spriteFacesLeft && startRight.Value){shouldTurn = true;}if (!spriteFacesLeft && startLeft.Value){shouldTurn = true;}}if (!startLeft.Value && !startRight.Value && !keepDirection.Value && UnityEngine.Random.Range(0f, 100f) <= 50f)//随机选择一边{shouldTurn = true;}startLeft.Value = false;startRight.Value = false;}public WalkLeftRight(){walkSpeed = 4f;groundLayer = "Terrain";turnDelay = 1f;}}}
整个PLAYmaker状态机如下所示:
二、制作敌人飞虫Fly
1.公式化导入制作飞虫Fly素材
这里就不过多赘述了,直接上图
这里需要注意到Fly有两个子游戏对象,用于检测是否碰到其它敌人需要转向,只不过这些都是后面设计要用的,所以先不管:
还有就是我们要开始导入PlayMaker Unity 2D用于检测场景中涉及到playmaker 2d的物理碰撞:
这里是我已经导入了所以是灰色的,你导入后会发现多生成了一个预制体:
再给我们fly添加一个脚本叫PlayMakerUnity2DProxy.cs:
2.制作敌人飞虫Fly的playmaker状态机
完成上述过程中就到了创建playmaker状态机环节,在这里我只用一个playmaker状态机完成Fly完整的循环:
变量和事件如下所示:
此时还需要继续自定义脚本,这就要用到上面提到的 playmaker 2d的物理碰撞了:
using UnityEngine;
using System.Collections.Generic;
using System;namespace HutongGames.PlayMaker.Actions
{[ActionCategory(ActionCategory.Physics)][Tooltip("Detect additional collisions between the Owner of this FSM and other object with additional raycasting.")]public class CheckCollisionSideEnter : FsmStateAction{[UIHint(UIHint.Variable)]public FsmBool topHit;[UIHint(UIHint.Variable)]public FsmBool rightHit;[UIHint(UIHint.Variable)]public FsmBool bottomHit;[UIHint(UIHint.Variable)]public FsmBool leftHit;public FsmEvent topHitEvent;public FsmEvent rightHitEvent;public FsmEvent bottomHitEvent;public FsmEvent leftHitEvent;public bool otherLayer;public int otherLayerNumber;public FsmBool ignoreTriggers;private PlayMakerUnity2DProxy _proxy;private Collider2D col2d;private const float RAYCAST_LENGTH = 0.08f;private List<Vector2> topRays;private List<Vector2> rightRays;private List<Vector2> bottomRays;private List<Vector2> leftRays;public override void Reset(){}public override void OnEnter(){col2d = Fsm.GameObject.GetComponent<Collider2D>();_proxy = Owner.GetComponent<PlayMakerUnity2DProxy>();if(_proxy == null){_proxy = Owner.AddComponent<PlayMakerUnity2DProxy>();}_proxy.AddOnCollisionEnter2dDelegate(new PlayMakerUnity2DProxy.OnCollisionEnter2dDelegate(DoCollisionEnter2D));}public override void OnUpdate(){ }public override void OnExit(){_proxy.RemoveOnCollisionEnter2dDelegate(new PlayMakerUnity2DProxy.OnCollisionEnter2dDelegate(DoCollisionEnter2D));}public new void DoCollisionEnter2D(Collision2D collision){if (!otherLayer){if(LayerMask.LayerToName(collision.gameObject.layer) == "Terrain"){CheckTouching(LayerMask.NameToLayer("Terrain"));return;}}else{CheckTouching(otherLayerNumber);}}private void CheckTouching(LayerMask layer){topRays = new List<Vector2>();topRays.Add(new Vector2(col2d.bounds.min.x, col2d.bounds.max.y));topRays.Add(new Vector2(col2d.bounds.center.x, col2d.bounds.max.y));topRays.Add(col2d.bounds.max);rightRays = new List<Vector2>();rightRays.Add(col2d.bounds.max);rightRays.Add(new Vector2(col2d.bounds.max.x, col2d.bounds.center.y));rightRays.Add(new Vector2(col2d.bounds.max.x, col2d.bounds.min.y));bottomRays = new List<Vector2>();bottomRays.Add(new Vector2(col2d.bounds.min.x, col2d.bounds.min.y));bottomRays.Add(new Vector2(col2d.bounds.center.x, col2d.bounds.min.y));bottomRays.Add(col2d.bounds.min);leftRays = new List<Vector2>();leftRays.Add(col2d.bounds.min);leftRays.Add(new Vector2(col2d.bounds.min.x, col2d.bounds.center.y));leftRays.Add(new Vector2(col2d.bounds.min.x, col2d.bounds.max.y));topHit.Value = false;rightHit.Value = false;bottomHit.Value = false;leftHit.Value = false;foreach (Vector2 v in topRays){RaycastHit2D raycastHit2D = Physics2D.Raycast(v, Vector2.up, RAYCAST_LENGTH, 1 << layer);if(raycastHit2D.collider != null && (!ignoreTriggers.Value || !raycastHit2D.collider.isTrigger)){topHit.Value = true;Fsm.Event(topHitEvent);break;}}foreach (Vector2 v2 in rightRays){RaycastHit2D raycastHit2D2 = Physics2D.Raycast(v2, Vector2.right, RAYCAST_LENGTH, 1 << layer);if (raycastHit2D2.collider != null && (!ignoreTriggers.Value || !raycastHit2D2.collider.isTrigger)){rightHit.Value = true;Fsm.Event(rightHitEvent);break;}}foreach (Vector2 v3 in bottomRays){RaycastHit2D raycastHit2D3 = Physics2D.Raycast(v3, Vector2.down, RAYCAST_LENGTH, 1 << layer);if(raycastHit2D3.collider != null && (!ignoreTriggers.Value || !raycastHit2D3.collider.isTrigger)){bottomHit.Value = true;Fsm.Event(bottomHitEvent);break;}}foreach (Vector2 v4 in leftRays){RaycastHit2D raycastHit2D4 = Physics2D.Raycast(v4, Vector2.left, RAYCAST_LENGTH, 1 << layer);if (raycastHit2D4.collider != null && (!ignoreTriggers.Value || !raycastHit2D4.collider.isTrigger)){leftHit.Value = true;Fsm.Event(leftHitEvent);break;}}}}}
using UnityEngine;
using System.Collections.Generic;
using System;namespace HutongGames.PlayMaker.Actions
{[ActionCategory(ActionCategory.Physics)][Tooltip("Detect additional collisions between the Owner of this FSM and other object with additional raycasting.")]public class CheckCollisionSide : FsmStateAction{[UIHint(UIHint.Variable)]public FsmBool topHit;[UIHint(UIHint.Variable)]public FsmBool rightHit;[UIHint(UIHint.Variable)]public FsmBool bottomHit;[UIHint(UIHint.Variable)]public FsmBool leftHit;public FsmEvent topHitEvent;public FsmEvent rightHitEvent;public FsmEvent bottomHitEvent;public FsmEvent leftHitEvent;public bool otherLayer;public int otherLayerNumber;public FsmBool ignoreTriggers;private PlayMakerUnity2DProxy _proxy;private Collider2D col2d;private const float RAYCAST_LENGTH = 0.08f;private List<Vector2> topRays;private List<Vector2> rightRays;private List<Vector2> bottomRays;private List<Vector2> leftRays;private bool checkUp;private bool checkRight;private bool checkBottom;private bool checkLeft;public override void Reset(){checkUp = false;checkRight = false;checkBottom = false;checkLeft = false;}public override void OnEnter(){col2d = Fsm.GameObject.GetComponent<Collider2D>();topRays = new List<Vector2>(3);rightRays = new List<Vector2>(3);bottomRays = new List<Vector2>(3);leftRays = new List<Vector2>(3);_proxy = Owner.GetComponent<PlayMakerUnity2DProxy>();if (_proxy == null){_proxy = Owner.AddComponent<PlayMakerUnity2DProxy>();}_proxy.AddOnCollisionStay2dDelegate(new PlayMakerUnity2DProxy.OnCollisionStay2dDelegate(DoCollisionStay2D));if(!topHit.IsNone || topHitEvent != null){checkUp = true;}else{checkUp = false;}if (!rightHit.IsNone || rightHitEvent != null){checkRight = true;}else{checkRight = false;}if (!bottomHit.IsNone || bottomHitEvent != null){checkBottom = true;}else{checkBottom = false;}if (!leftHit.IsNone || leftHitEvent != null){checkLeft = true;}else{checkLeft = false;}}public override void OnUpdate(){if(topHit.Value || rightHit.Value || bottomHit.Value || leftHit.Value){if (!otherLayer){CheckTouching(LayerMask.NameToLayer("Terrain"));return;}CheckTouching(otherLayerNumber);} }public override void OnExit(){_proxy.RemoveOnCollisionStay2dDelegate(new PlayMakerUnity2DProxy.OnCollisionStay2dDelegate(DoCollisionStay2D));}public new void DoCollisionStay2D(Collision2D collision){if (!otherLayer){if(collision.gameObject.layer == LayerMask.NameToLayer("Terrain")){CheckTouching(LayerMask.NameToLayer("Terrain"));return;}}else{CheckTouching(otherLayerNumber);}}public new void DoCollisionExit2D(Collision2D collision){topHit.Value = false;rightHit.Value = false;bottomHit.Value = false;leftHit.Value = false;}private void CheckTouching(LayerMask layer){if (checkUp){topRays.Clear();topRays.Add(new Vector2(col2d.bounds.min.x, col2d.bounds.max.y));topRays.Add(new Vector2(col2d.bounds.center.x, col2d.bounds.max.y));topRays.Add(col2d.bounds.max);topHit.Value = false;for (int i = 0; i < 3; i++){RaycastHit2D raycastHit2D = Physics2D.Raycast(topRays[i], Vector2.up, RAYCAST_LENGTH, 1 << layer);if(raycastHit2D.collider != null && (!ignoreTriggers.Value || !raycastHit2D.collider.isTrigger)){topHit.Value = true;Fsm.Event(topHitEvent);break;}}}if (checkRight){rightRays.Clear();rightRays.Add(col2d.bounds.max);rightRays.Add(new Vector2(col2d.bounds.max.x, col2d.bounds.center.y));rightRays.Add(new Vector2(col2d.bounds.max.x, col2d.bounds.min.y));rightHit.Value = false;for (int i = 0; i < 3; i++){RaycastHit2D raycastHit2D2 = Physics2D.Raycast(rightRays[i], Vector2.right, RAYCAST_LENGTH, 1 << layer);if (raycastHit2D2.collider != null && (!ignoreTriggers.Value || !raycastHit2D2.collider.isTrigger)){rightHit.Value = true;Fsm.Event(rightHitEvent);break;}}}if (checkBottom){bottomRays.Clear();bottomRays.Add(new Vector2(col2d.bounds.min.x, col2d.bounds.min.y));bottomRays.Add(new Vector2(col2d.bounds.center.x, col2d.bounds.min.y));bottomRays.Add(col2d.bounds.min);for (int i = 0; i < 3; i++){RaycastHit2D raycastHit2D3 = Physics2D.Raycast(bottomRays[i], Vector2.down, RAYCAST_LENGTH, 1 << layer);if (raycastHit2D3.collider != null && (!ignoreTriggers.Value || !raycastHit2D3.collider.isTrigger)){bottomHit.Value = true;Fsm.Event(bottomHitEvent);break;}}}if (checkLeft){leftRays.Clear();leftRays.Add(col2d.bounds.min);leftRays.Add(new Vector2(col2d.bounds.min.x, col2d.bounds.center.y));leftRays.Add(new Vector2(col2d.bounds.min.x, col2d.bounds.max.y));for (int i = 0; i < 3; i++){RaycastHit2D raycastHit2D4 = Physics2D.Raycast(leftRays[i], Vector2.left, RAYCAST_LENGTH, 1 << layer);if (raycastHit2D4.collider != null && (!ignoreTriggers.Value || !raycastHit2D4.collider.isTrigger)){leftHit.Value = true;Fsm.Event(leftHitEvent);return;}}}}public enum CollisionSide { top,left,right,bottom,other}}}
using System;
using UnityEngine;namespace HutongGames.PlayMaker.Actions
{[ActionCategory(ActionCategory.Physics2D)][Tooltip("Sets the 2d Velocity of a Game Object, using an angle and a speed value. For the angle, 0 is to the right and the degrees increase clockwise.")]public class SetVelocityAsAngle : RigidBody2dActionBase{[RequiredField][CheckForComponent(typeof(Rigidbody2D))]public FsmOwnerDefault gameObject;[RequiredField]public FsmFloat angle;[RequiredField]public FsmFloat speed;private FsmFloat x;private FsmFloat y;public bool everyFrame;public override void Reset(){gameObject = null;angle = new FsmFloat{UseVariable = true};speed = new FsmFloat{UseVariable = true};everyFrame = false;}public override void Awake(){Fsm.HandleFixedUpdate = true;}public override void OnPreprocess(){Fsm.HandleFixedUpdate = true;}public override void OnEnter(){CacheRigidBody2d(Fsm.GetOwnerDefaultTarget(gameObject));DoSetVelocity();if (!everyFrame){Finish();}}public override void OnFixedUpdate(){DoSetVelocity();if (!everyFrame){Finish();}}private void DoSetVelocity(){if (rb2d == null)return;x = speed.Value * Mathf.Cos(angle.Value * 0.017453292f); //将角度转化为速度y = speed.Value * Mathf.Sin(angle.Value * 0.017453292f);Vector2 velocity;velocity.x = x.Value;velocity.y = y.Value;rb2d.velocity = velocity;}}}
整个Playmaker状态机如下所示:
完整图如下所示:
总结
首先我们来看看Crawler的转向效果能不能实现:
我们再来看看Fly的状态机能不能正常运行:
我们可以创建一个闭环的四边形,并给他一个"Terrain"Layer
完美运行,下一期我们来丰富一下玩家的行为吧。
相关文章:

[Unity Demo]从零开始制作空洞骑士Hollow Knight第五集:再制作更多的敌人
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、制作敌人另个爬虫Crawler 1.公式化导入制作另个爬虫Crawler素材2.制作另个爬虫Crawler的Crawler.cs状态机3.制作敌人另个爬虫Crawler的playmaker状态机二、…...

怎么把excel翻译成英文?这些翻译技巧记得收藏
在处理Excel数据时,我们常常会遇到多语言的数据集,这无疑给数据分析和整理带来了不小的挑战。 幸运的是,随着技术的发展,现在有多种工具可以帮助我们进行Excel中的批量翻译,这些工具以其强大的翻译功能和便捷的操作方…...
信息技术引领的智能化未来
信息技术引领的智能化未来 随着信息技术的飞速发展,社会各个领域正在加速迈入智能化的新时代。信息技术的广泛应用,尤其是人工智能、大数据、物联网等前沿技术的创新与融合,正在从根本上改变着人们的生产和生活方式。本文将探讨信息技术在智…...

【QT开发-Pyside】使用Pycharm与conda配置Pyside环境并新建工程
知识拓展 Pycharm 是一个由 JetBrains 开发的集成开发环境(IDE),它主要用于 Python 编程语言的开发。Pycharm 提供了代码编辑、调试、版本控制、测试等多种功能,以提高 Python 开发者的效率。 Pycharm 与 Python 的关系 Pycharm 是…...
vue选项式写法项目案例(购物车)
一、初始化项目结构 1.初始化vite项目 npm create vite cd vite-project npm install 2.清理项目结构 清空App.vue 删除components目录下的HelloWorld.vue组件 3.为组件的样式启用sacc或less组件 npm i sass4.初始化index.css全局样式 :root{font-size:12px } 二、封装…...

[Linux][进程] 认识进程
基本概念 进程是一个操作系统术语,用来管理与操作程序.在windows下打开任务管理器即可查看目前打开的所有进程 PCB 进程控制块,从代码层面来说 PCB 是进程所有属性的一个结构体,在Linux源码中PCB指的是struct task_struct. Linux环境下: 进程 task_struct 代码 …...

如何安装和注册 GitLab Runner
如何安装和注册 GitLab Runner GitLab Runner 是一个用于运行 GitLab CI/CD (Continuous Integration/Continuous Deployment) 作业。它是一个与 GitLab 配合使用的应用程序,可以在本地或云中运行。Runner 可以执行不同类型的作业,例如编译代码、运行测…...

专业学习|动态规划(概念、模型特征、解题步骤及例题)
一、引言 (一)从斐波那契数列引入自底向上算法 (1)知识讲解 (2)matlap实现递归 (3)带有备忘录的遗传算法 (4)matlap实现带有备忘录的递归算法 “࿱…...

数据结构与算法 #时间复杂度 #空间复杂度
文章目录 前言 一、算法的复杂度 二、时间复杂度 三、空间复杂度 四、例题 1、例1:冒泡排序 2、例2: 3、例3: 4、例4: 二分查找 5、例5: 阶乘 6、例6: 斐波那契 五、常见算法复杂度 总结 前言 路漫漫其修远兮,吾将上下而求索&…...
【多机器人轨迹规划最优解问题】
此类应用场景通常很难有严格意义上的最优解,一般只能得到较优解。限制其获得最优解的主要因素如下: 一、问题的复杂性 多机器人系统的高维度性:每台机器人都有自己的位置、速度、任务等多个状态变量,多台机器人组合在一起使得问…...
机器学习及其应用领域【金融领域】
机器学习及其应用领域【金融领域】 一、智能投顾与资产配置二、信贷审批与风险评估三、支付与交易安全四、金融欺诈检测五、市场预测与情绪分析六、客户服务与个性化推荐七、面临的挑战与未来趋势八、总结 一、智能投顾与资产配置 智能投顾:通过机器学习技术&#…...

【实战教程】PHP与七牛云的完美对接,你值得拥有!
前言: 随着互联网的迅速发展,越来越多的网站和应用程序需要处理大量的图片、视频和其他文件。为了有效地存储和管理这些文件,并提供快速的内容分发服务,开发者们常常依赖于云存储和CDN服务提供商。 七牛云是一家领先的云存储和CD…...

2024网易低代码大赛 | 想参赛但不知道搭什么?灵感就这么水灵灵地来了!
9月6日-10月15日,报名进行时!戳我即可报名! 如果你还没想好要开发什么作品来参赛,那就必须往下 我们采访了n位网易内部人士,搜罗了他们的建议,给你多一些灵感! 注意:下文仅为本次比赛…...

(附源码)基于django的电力工程作业现场物资管理系统的设计与实现-计算机毕设 22067
基于django的电力工程作业现场物资管理系统的设计与实现 摘 要 随着电力工程的快速发展,作业现场物资管理成为保障工程进度和质量的关键环节。本文旨在设计并实现一个基于Django框架的电力工程作业现场物资管理系统,以提高物资管理的效率和准确性。该系统…...

数据链路层协议 —— 以太网协议
目录 1.数据链路层解决的问题 2.局域网通信方式 以太网 令牌环网 无线局域网 3.以太网协议 以太网帧格式 对比理解Mac地址和IP地址 认识MTU MTU对IP协议的影响 MTU对UDP的影响 MTU对TCP的影响 基于以太网协议的报文转发流程 交换机的工作原理 4.ARP协议 ARP协议…...
【Javascript】一文看懂JS中的symbol到底是什么东西
作为一名经验丰富的 JavaScript 开发者,你可能对 JavaScript 中的各种数据类型已经了如指掌,比如数字、字符串、布尔值和对象。但是你知道吗?JavaScript 还有一种叫做 Symbol 的类型。在这篇文章里,我们将深入探讨 Symbol 的世界&…...
go语言网络编程
网络编程Go语言网络编程相关APIGo语言网络编程架构Go语言的网络编程实现基于以下几个关键原理:bufiobufio 包的主要功能和使用场景主要类型示例 tcp通信解决粘包粘包和拆包的产生原因解决方法示例 网络编程 Go语言网络编程相关API 1.1 net包net.Listen(network, a…...

LeetcodeLCR 116. 省份数量
文章目录 题目原题链接思路C代码 题目 原题链接 LCR 116. 省份数量 思路 利用并查集的思想,将连接的诚实放在一个集合当中,最后遍历并查集数组判断有几颗树 初始化一个并查集;将连通的城市合并;统计并查集中树的个数;…...

Linux系统上搭建Vulhub靶场
Linux系统上搭建Vulhub靶场 vulhub 是一个开源的漏洞靶场,它提供了各种易受攻击的服务和应用程序,供安全研究人员和学习者测试和练习。要在 Linux 系统上安装和运行 vulhub,可以按照以下步骤进行: 1. 安装 Docker 和 Docke…...
Avalonia的第三方UI库SukiUI详细教程
文章目录 一、SukiUI 简介二、安装与配置1、安装 SukiUI 库:2、配置 Avalonia 项目以使用 SukiUI:三、基本组件使用1、按钮(SukiButton):2、文本框(SukiTextBox):3、标签(SukiLabel):4、下拉列表(SukiComboBox):四、布局与容器1、布局容器介绍:2、使用布局容器组…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...