[Unity Demo]从零开始制作空洞骑士Hollow Knight第十八集补充:制作空洞骑士独有的EventSystem和InputModule

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、制作空洞骑士独有的EventSystem和InputModule
  • 总结


前言

        hello大家好久没见,之所以隔了这么久才更新并不是因为我又放弃了这个项目,而是接下来要制作的工作太忙碌了,每次我都花了很长的时间解决完一个部分,然后就没力气打开CSDN写文章就直接睡觉去了,现在终于有时间整理下我这半个月都做了什么内容。

       那么这一期的标题是什么意思呢?就是我之前漏讲了UI当中非常关键的EventSystem和InputModule,没有这两个组件Unity的UI是不会自动进行UI的导航,点击后的事件啥的,而你创建一个canvas,unity会自动生成了一个eventsystem,但是Input Module则是绑定的是Unity最传统的Input Manager,如果你用过前两三年前unity推出的input system的话,你知道它们是要求你替换到input system独有的input module的,

        既然我们是使用插件InControl来作为输入控制,我们也要生成一个空洞骑士独有的UI输入木块。

一、pandas是什么?

        首先来创建一个类名字叫HollowKnightInputModule.cs,然后它的代码逻辑整体是根据UnityEngine.EventSystems里面的StandaloneInputModule.cs来写的,如果不了解的话建议先了解一下unity自带的input module的源码。

        

using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;

namespace InControl
{
    [AddComponentMenu("Event/Hollow Knight Input Module")]
    public class HollowKnightInputModule : StandaloneInputModule
    {
	public HeroActions heroActions;
	public PlayerAction SubmitAction 
	{
	    get
	    {
		return InputHandler.Instance.inputActions.menuSubmit;
	    }
	    set
	    {

	    }
	}
	public PlayerAction CancelAction {
	    get
	    {
		return InputHandler.Instance.inputActions.menuCancel;
	    }
	    set
	    {

	    }
	}
	public PlayerAction JumpAction {
	    get
	    {
		return InputHandler.Instance.inputActions.jump;
	    }
	    set
	    {

	    }
	}
	public PlayerAction CastAction {
	    get
	    {
		return InputHandler.Instance.inputActions.cast;
	    }
	    set
	    {

	    }
	}
	public PlayerAction AttackAction {
	    get
	    {
		return InputHandler.Instance.inputActions.attack;
	    }
	    set
	    {

	    }
	}
	public PlayerTwoAxisAction MoveAction {
	    get
	    {
		return InputHandler.Instance.inputActions.moveVector;
	    }
	    set
	    {

	    }
	}

	[Range(0.1f, 0.9f)]
	public float analogMoveThreshold = 0.5f;
	public float moveRepeatFirstDuration = 0.8f;
	public float moveRepeatDelayDuration = 0.1f;

	[FormerlySerializedAs("allowMobileDevice")]
	public new bool forceModuleActive;
	public bool allowMouseInput = true;
	public bool focusOnMouseHover;

	private InputDevice inputDevice;
	private Vector3 thisMousePosition;
	private Vector3 lastMousePosition;
	private Vector2 thisVectorState;
	private Vector2 lastVectorState;
	private float nextMoveRepeatTime;
	private float lastVectorPressedTime;
	private TwoAxisInputControl direction;

	public HollowKnightInputModule()
	{
	    heroActions = new HeroActions();
	    direction = new TwoAxisInputControl();
	    direction.StateThreshold = analogMoveThreshold;
	}
	public override void UpdateModule()
	{
	    lastMousePosition = thisMousePosition;
	    thisMousePosition = Input.mousePosition;
	}

	public override bool IsModuleSupported()
	{
	    return forceModuleActive || Input.mousePresent;
	}

	public override bool ShouldActivateModule()
	{
	    if (!enabled || !gameObject.activeInHierarchy)
	    {
		return false;
	    }
	    UpdateInputState();
	    bool flag = false;
	    flag |= SubmitAction.WasPressed;
	    flag |= CancelAction.WasPressed;
	    flag |= JumpAction.WasPressed;
	    flag |= CastAction.WasPressed;
	    flag |= AttackAction.WasPressed;
	    flag |= VectorWasPressed;
	    if (allowMouseInput)
	    {
		flag |= MouseHasMoved;
		flag |= MouseButtonIsPressed;
	    }
	    if (Input.touchCount > 0)
	    {
		flag = true;
	    }
	    return flag;
	}

	public override void ActivateModule()
	{
	    base.ActivateModule();
	    thisMousePosition = Input.mousePosition;
	    lastMousePosition = Input.mousePosition;
	    GameObject gameObject = eventSystem.currentSelectedGameObject;
	    if (gameObject == null)
	    {
		gameObject = eventSystem.firstSelectedGameObject;
	    }
	    eventSystem.SetSelectedGameObject(gameObject, GetBaseEventData());
	}

	public override void Process()
	{
	    bool flag = SendUpdateEventToSelectedObject();
	    if (eventSystem.sendNavigationEvents)
	    {
		if (!flag)
		{
		    flag = SendVectorEventToSelectedObject();
		}
		if (!flag)
		{
		    SendButtonEventToSelectedObject();
		}
	    }
	    if (allowMouseInput)
	    {
		ProcessMouseEvent();
	    }
	}

	private bool SendButtonEventToSelectedObject()
	{
	    if (eventSystem.currentSelectedGameObject == null)
	    {
		return false;
	    }
	    if (UIManager.instance.IsFadingMenu)
	    {
		return false;
	    }
	    BaseEventData baseEventData = GetBaseEventData();
	    Platform.MenuActions menuAction = Platform.Current.GetMenuAction(SubmitAction.WasPressed, CancelAction.WasPressed, JumpAction.WasPressed, AttackAction.WasPressed, CastAction.WasPressed);
	    if (menuAction == Platform.MenuActions.Submit)
	    {
		ExecuteEvents.Execute<ISubmitHandler>(eventSystem.currentSelectedGameObject, baseEventData, ExecuteEvents.submitHandler);
	    }
	    else if (menuAction == Platform.MenuActions.Cancel)
	    {
		PlayerAction playerAction = AttackAction.WasPressed ? AttackAction : CastAction;
		if (!playerAction.WasPressed || playerAction.FindBinding(new MouseBindingSource(Mouse.LeftButton)) == null)
		{
		    ExecuteEvents.Execute<ICancelHandler>(eventSystem.currentSelectedGameObject, baseEventData, ExecuteEvents.cancelHandler);
		}
	    }
	    return baseEventData.used;
	}

	private bool SendVectorEventToSelectedObject()
	{
	    if (!VectorWasPressed)
	    {
		return false;
	    }
	    AxisEventData axisEventData = GetAxisEventData(thisVectorState.x, thisVectorState.y, 0.5f);
	    if (axisEventData.moveDir != MoveDirection.None)
	    {
		if (eventSystem.currentSelectedGameObject == null)
		{
		    eventSystem.SetSelectedGameObject(eventSystem.firstSelectedGameObject, GetBaseEventData());
		}
		else
		{
		    ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, axisEventData, ExecuteEvents.moveHandler);
		}
		SetVectorRepeatTimer();
	    }
	    return axisEventData.used;
	}

	protected override void ProcessMove(PointerEventData pointerEvent)
	{
	    GameObject pointerEnter = pointerEvent.pointerEnter;
	    base.ProcessMove(pointerEvent);
	    if (focusOnMouseHover && pointerEnter != pointerEvent.pointerEnter)
	    {
		GameObject eventHandler = ExecuteEvents.GetEventHandler<ISelectHandler>(pointerEvent.pointerEnter);
		eventSystem.SetSelectedGameObject(eventHandler, pointerEvent);
	    }
	}

	private void Update()
	{
	    direction.Filter(Device.Direction, Time.deltaTime);
	}

	private void UpdateInputState()
	{
	    lastVectorState = thisVectorState;
	    thisVectorState = Vector2.zero;
	    TwoAxisInputControl twoAxisInputControl = MoveAction ?? direction;
	    if (Utility.AbsoluteIsOverThreshold(twoAxisInputControl.X, analogMoveThreshold))
	    {
		thisVectorState.x = Mathf.Sign(twoAxisInputControl.X);
	    }
	    if (Utility.AbsoluteIsOverThreshold(twoAxisInputControl.Y, analogMoveThreshold))
	    {
		thisVectorState.y = Mathf.Sign(twoAxisInputControl.Y);
	    }
	    if (VectorIsReleased)
	    {
		nextMoveRepeatTime = 0f;
	    }
	    if (VectorIsPressed)
	    {
		if (lastVectorState == Vector2.zero)
		{
		    if (Time.realtimeSinceStartup > lastVectorPressedTime + 0.1f)
		    {
			nextMoveRepeatTime = Time.realtimeSinceStartup + moveRepeatFirstDuration;
		    }
		    else
		    {
			nextMoveRepeatTime = Time.realtimeSinceStartup + moveRepeatDelayDuration;
		    }
		}
		lastVectorPressedTime = Time.realtimeSinceStartup;
	    }
	}

	public InputDevice Device
	{
	    get
	    {
		return inputDevice ?? InputManager.ActiveDevice;
	    }
	    set
	    {
		inputDevice = value;
	    }
	}

	private void SetVectorRepeatTimer()
	{
	    nextMoveRepeatTime = Mathf.Max(nextMoveRepeatTime, Time.realtimeSinceStartup + moveRepeatDelayDuration);
	}

	private bool VectorIsPressed
	{
	    get
	    {
		return thisVectorState != Vector2.zero;
	    }
	}

	private bool VectorIsReleased
	{
	    get
	    {
		return thisVectorState == Vector2.zero;
	    }
	}

	private bool VectorHasChanged
	{
	    get
	    {
		return thisVectorState != lastVectorState;
	    }
	}


	private bool VectorWasPressed
	{
	    get
	    {
		return (VectorIsPressed && Time.realtimeSinceStartup > nextMoveRepeatTime) || (VectorIsPressed && lastVectorState == Vector2.zero);
	    }
	}

	private bool MouseHasMoved
	{
	    get
	    {
		return (thisMousePosition - lastMousePosition).sqrMagnitude > 0f;
	    }
	}

	private bool MouseButtonIsPressed
	{
	    get
	    {
		return Input.GetMouseButtonDown(0);
	    }
	}
    }
}

这里涉及到我们InputActions.cs和InputHandler.cs代码相关的:

我们先来到HeroActions.cs,创建好menuUI的按键输入:

using System;
using InControl;

public class HeroActions : PlayerActionSet
{
    public PlayerAction left;
    public PlayerAction right;
    public PlayerAction up;
    public PlayerAction down;
    public PlayerAction menuSubmit;
    public PlayerAction menuCancel;
    public PlayerTwoAxisAction moveVector;
    public PlayerAction attack;
    public PlayerAction jump;
    public PlayerAction dash;
    public PlayerAction cast;
    public PlayerAction focus;
    public PlayerAction quickCast;
    public PlayerAction openInventory;


    public HeroActions()
    {
	menuSubmit = CreatePlayerAction("Submit");
	menuCancel = CreatePlayerAction("Cancel");
	left = CreatePlayerAction("Left");
	left.StateThreshold = 0.3f;
	right = CreatePlayerAction("Right");
	right.StateThreshold = 0.3f;
	up = CreatePlayerAction("Up");
	up.StateThreshold = 0.3f;
	down = CreatePlayerAction("Down");
	down.StateThreshold = 0.3f;
	moveVector = CreateTwoAxisPlayerAction(left, right, down, up);
	moveVector.LowerDeadZone = 0.15f;
	moveVector.UpperDeadZone = 0.95f;
	attack = CreatePlayerAction("Attack");
	jump = CreatePlayerAction("Jump");
	dash = CreatePlayerAction("Dash");
	cast = CreatePlayerAction("Cast");
	focus = CreatePlayerAction("Focus");
	quickCast = CreatePlayerAction("QuickCast");
	openInventory = CreatePlayerAction("Inventory");
    }
}

来到InputHandler.cs当中,我们要做的功能如下,首先当然是添加新的按键绑定AddKeyBinding,还有添加新的默认绑定AddDefaultBinding,特别是我们新建的两个行为PlayerAction的menuCancel和menuSubmit

  private void MapKeyboardLayoutFromGameSettings()
    {
	AddKeyBinding(inputActions.menuSubmit, "Return");
	AddKeyBinding(inputActions.menuCancel, "Escape");
	AddKeyBinding(inputActions.up, "UpArrow");
	AddKeyBinding(inputActions.down, "DownArrow");
	AddKeyBinding(inputActions.left, "LeftArrow");
	AddKeyBinding(inputActions.right, "RightArrow");
	AddKeyBinding(inputActions.attack, "Z");
	AddKeyBinding(inputActions.jump, "X");
	AddKeyBinding(inputActions.dash, "D");
	AddKeyBinding(inputActions.cast, "F");
	AddKeyBinding(inputActions.quickCast, "Q");
	AddKeyBinding(inputActions.openInventory, "I");
    }

    private void SetupNonMappableBindings()
    {
	inputActions = new HeroActions();
	inputActions.menuSubmit.AddDefaultBinding(new Key[]
	{
	    Key.Return
	});
	inputActions.menuCancel.AddDefaultBinding(new Key[]
	{
	    Key.Escape
	});
	inputActions.up.AddDefaultBinding(new Key[]
	{
	    Key.UpArrow
	});
	inputActions.down.AddDefaultBinding(new Key[]
	{
	    Key.DownArrow
	});
	inputActions.left.AddDefaultBinding(new Key[]
	{
	    Key.LeftArrow
	});
	inputActions.right.AddDefaultBinding(new Key[]
	{
	    Key.RightArrow
	});
	inputActions.attack.AddDefaultBinding(new Key[]
	{
	    Key.Z
	});
	inputActions.jump.AddDefaultBinding(new Key[]
	{
	    Key.X
	});
	inputActions.dash.AddDefaultBinding(new Key[]
	{
	    Key.D
	});
	inputActions.cast.AddDefaultBinding(new Key[]
	{
	    Key.F
	});
	inputActions.quickCast.AddDefaultBinding(new Key[]
	{
	    Key.Q
	});
	inputActions.openInventory.AddDefaultBinding(new Key[]
	{
	    Key.I
	});
    }


    private static void AddKeyBinding(PlayerAction action, string savedBinding)
    {
	Mouse mouse = Mouse.None;
	Key key;
	if (!Enum.TryParse(savedBinding, out key) && !Enum.TryParse(savedBinding, out mouse))
	{
	    return;
	}
	if (mouse != Mouse.None)
	{
	    action.AddBinding(new MouseBindingSource(mouse));
	    return;
	}
	action.AddBinding(new KeyBindingSource(new Key[]
	{
	    key
	}));
    }

还有就是解决上期忘记讲到的两套Input输入一个是游戏内的输入,一个是过场的输入,当在过场UI阶段,我们就使用过场的输入,屏蔽游戏内的输入,然后是决定UI界面的输入和停止UI界面的输入,完整的代码如下:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using GlobalEnums;
using InControl;
using UnityEngine;
using UnityEngine.EventSystems;

public class InputHandler : MonoBehaviour
{
    [SerializeField] public bool pauseAllowed { get; private set; }
    public bool acceptingInput = true;

    public bool skippingCutscene;
    private float skipCooldownTime;

    private bool isGameplayScene;
    private bool isMenuScene;

    public static InputHandler Instance;
    private GameManager gm;
    private PlayerData playerData;

    public InputDevice gameController;
    public HeroActions inputActions;

    public BindingSourceType lastActiveController;
    public InputDeviceStyle lastInputDeviceStyle;

    public delegate void CursorVisibilityChange(bool isVisible); //指针显示变化时发生的委托
    public event CursorVisibilityChange OnCursorVisibilityChange;//指针显示变化时发生的事件

    public bool readyToSkipCutscene;
    public SkipPromptMode skipMode { get; private set; }

    public delegate void ActiveControllerSwitch();
    public event ActiveControllerSwitch RefreshActiveControllerEvent;

    public void Awake()
    {
	Instance = this;
	gm = GetComponent<GameManager>();
	inputActions = new HeroActions();
	acceptingInput = true;
	pauseAllowed = true;
	skipMode = SkipPromptMode.NOT_SKIPPABLE;

    }

    public void Start()
    {
	playerData = gm.playerData;
	SetupNonMappableBindings();
	MapKeyboardLayoutFromGameSettings();
	if(InputManager.ActiveDevice != null && InputManager.ActiveDevice.IsAttached)
	{

	}
	else
	{
	    gameController = InputDevice.Null;
	}
	Debug.LogFormat("Input Device set to {0}.", new object[]
	{
	    gameController.Name
	});
	lastActiveController = BindingSourceType.None;
    }

    private void Update()
    {
	UpdateActiveController();
	if (acceptingInput)
	{
	    if(gm.gameState == GameState.PLAYING)
	    {
		PlayingInput();
	    }
	    else if(gm.gameState == GameState.CUTSCENE)
	    {
		CutSceneInput();
	    }
	}
    }

    public void UpdateActiveController()
    {
	if (lastActiveController != inputActions.LastInputType || lastInputDeviceStyle != inputActions.LastDeviceStyle)
	{
	    lastActiveController = inputActions.LastInputType;
	    lastInputDeviceStyle = inputActions.LastDeviceStyle;
	    if (RefreshActiveControllerEvent != null)
	    {
		RefreshActiveControllerEvent();
	    }
	}
    }
    private void PlayingInput()
    {

    }

    private void CutSceneInput()
    {
	if (!Input.anyKeyDown && !gameController.AnyButton.WasPressed)
	{
	    return;
	}
	if (skippingCutscene)
	{
	    return;
	}
	switch (skipMode)
	{
	    case SkipPromptMode.SKIP_PROMPT: //确认跳过过场
		if (!readyToSkipCutscene)
		{
		    //TODO:
		    gm.ui.ShowCutscenePrompt(CinematicSkipPopup.Texts.Skip);
		    readyToSkipCutscene = true;
		    CancelInvoke("StopCutsceneInput");
		    Invoke("StopCutsceneInput", 5f * Time.timeScale);
		    skipCooldownTime = Time.time + 0.3f;
		    return;
		}
		if(Time.time < skipCooldownTime)
		{
		    return;
		}
		CancelInvoke("StopCutsceneInput");
		readyToSkipCutscene = false;
		skippingCutscene = true;
		gm.SkipCutscene();
		return;
	    case SkipPromptMode.SKIP_INSTANT://立刻跳过过场
		skippingCutscene = true;
		gm.SkipCutscene();
		return;
	    case SkipPromptMode.NOT_SKIPPABLE: //不准跳过过场
		return;
	    case SkipPromptMode.NOT_SKIPPABLE_DUE_TO_LOADING: //在过场视频加载的时候不准跳过过场
		gm.ui.ShowCutscenePrompt(CinematicSkipPopup.Texts.Skip);
		CancelInvoke("StopCutsceneInput");
		Invoke("StopCutsceneInput", 5f * Time.timeScale);
		break;
	    default:
		return;
	}
    }

    private void StopCutsceneInput()
    {
	readyToSkipCutscene = false;
	gm.ui.HideCutscenePrompt();
    }

    private void MapKeyboardLayoutFromGameSettings()
    {
	AddKeyBinding(inputActions.menuSubmit, "Return");
	AddKeyBinding(inputActions.menuCancel, "Escape");
	AddKeyBinding(inputActions.up, "UpArrow");
	AddKeyBinding(inputActions.down, "DownArrow");
	AddKeyBinding(inputActions.left, "LeftArrow");
	AddKeyBinding(inputActions.right, "RightArrow");
	AddKeyBinding(inputActions.attack, "Z");
	AddKeyBinding(inputActions.jump, "X");
	AddKeyBinding(inputActions.dash, "D");
	AddKeyBinding(inputActions.cast, "F");
	AddKeyBinding(inputActions.quickCast, "Q");
	AddKeyBinding(inputActions.openInventory, "I");
    }

    private void SetupNonMappableBindings()
    {
	inputActions = new HeroActions();
	inputActions.menuSubmit.AddDefaultBinding(new Key[]
	{
	    Key.Return
	});
	inputActions.menuCancel.AddDefaultBinding(new Key[]
	{
	    Key.Escape
	});
	inputActions.up.AddDefaultBinding(new Key[]
	{
	    Key.UpArrow
	});
	inputActions.down.AddDefaultBinding(new Key[]
	{
	    Key.DownArrow
	});
	inputActions.left.AddDefaultBinding(new Key[]
	{
	    Key.LeftArrow
	});
	inputActions.right.AddDefaultBinding(new Key[]
	{
	    Key.RightArrow
	});
	inputActions.attack.AddDefaultBinding(new Key[]
	{
	    Key.Z
	});
	inputActions.jump.AddDefaultBinding(new Key[]
	{
	    Key.X
	});
	inputActions.dash.AddDefaultBinding(new Key[]
	{
	    Key.D
	});
	inputActions.cast.AddDefaultBinding(new Key[]
	{
	    Key.F
	});
	inputActions.quickCast.AddDefaultBinding(new Key[]
	{
	    Key.Q
	});
	inputActions.openInventory.AddDefaultBinding(new Key[]
	{
	    Key.I
	});
    }


    private static void AddKeyBinding(PlayerAction action, string savedBinding)
    {
	Mouse mouse = Mouse.None;
	Key key;
	if (!Enum.TryParse(savedBinding, out key) && !Enum.TryParse(savedBinding, out mouse))
	{
	    return;
	}
	if (mouse != Mouse.None)
	{
	    action.AddBinding(new MouseBindingSource(mouse));
	    return;
	}
	action.AddBinding(new KeyBindingSource(new Key[]
	{
	    key
	}));
    }

    public void SceneInit()
    {
	if (gm.IsGameplayScene())
	{
	    isGameplayScene = true;
	}
	else
	{
	    isGameplayScene = false;
	}
	if (gm.IsMenuScene())
	{
	    isMenuScene = true;
	}
	else
	{
	    isMenuScene = false;
	}
    }

    public void SetSkipMode(SkipPromptMode newMode)
    {
	Debug.Log("Setting skip mode: " + newMode.ToString());
	if (newMode == SkipPromptMode.NOT_SKIPPABLE)
	{
	    StopAcceptingInput();
	}
	else if (newMode == SkipPromptMode.SKIP_PROMPT)
	{
	    readyToSkipCutscene = false;
	    StartAcceptingInput();
	}
	else if (newMode == SkipPromptMode.SKIP_INSTANT)
	{
	    StartAcceptingInput();
	}
	else if (newMode == SkipPromptMode.NOT_SKIPPABLE_DUE_TO_LOADING)
	{
	    readyToSkipCutscene = false;
	    StartAcceptingInput();
	}
	skipMode = newMode;
    }


    public void StopUIInput()
    {
	acceptingInput = false;
	EventSystem.current.sendNavigationEvents = false;
	UIManager.instance.inputModule.allowMouseInput = false;
    }

    public void StartUIInput()
    {
	acceptingInput = true;
	EventSystem.current.sendNavigationEvents = true;
	UIManager.instance.inputModule.allowMouseInput = true;
    }

    public void StopMouseInput()
    {
	UIManager.instance.inputModule.allowMouseInput = false;
    }

    public void StartMouseInput()
    {
	UIManager.instance.inputModule.allowMouseInput = true;
    }

    public void PreventPause()
    {
	
    }

    public void StopAcceptingInput()
    {
	acceptingInput = false;
    }

    public void StartAcceptingInput()
    {
	acceptingInput = true;
    }

    public void AllowPause()
    {
	pauseAllowed = true;
    }

}

回到编辑器当中,我们来给UIManager的EventSystem添加上这两个脚本:


总结

        OK大功告成,这期算是对前两期的补充内容了,如果你在前两期遇到bug的话可以在这里找下解决办法。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

K8S群集调度二

一、污点(Taint) 和 容忍(Tolerations) 1.1、污点(Taint) 设置在node上是对pod的一种作用 节点的亲和性&#xff0c;是Pod的一种属性&#xff08;偏好或硬性要求&#xff09;&#xff0c;它使Pod被吸引到一类特定的节点 而Taint 则相反&#xff0c;它使节点能够排斥一类特…

MySQL45讲 第十六讲 “order by”是怎么工作的?

文章目录 MySQL45讲 第十六讲 “order by”是怎么工作的&#xff1f;一、引言二、全字段排序&#xff08;一&#xff09;索引创建与执行情况分析&#xff08;二&#xff09;执行流程&#xff08;三&#xff09;查看是否使用临时文件 三、rowid 排序&#xff08;一&#xff09;参…

HTML 基础标签——结构化标签<html>、<head>、<body>

文章目录 1. <html> 标签2. <head> 标签3. <body> 标签4. <div> 标签5. <span> 标签小结 在 HTML 文档中&#xff0c;使用特定的结构标签可以有效地组织和管理网页内容。这些标签不仅有助于浏览器正确解析和渲染页面&#xff0c;还能提高网页的可…

【原创】java+ssm+mysql电费管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

浅谈QT中Tab键的切换逻辑

浅谈QT中Tab键的切换逻辑 无意中发现在输入界面中按下Tab键时&#xff0c;没有按照预想的顺序切换焦点事件&#xff0c;如下图所示 这个现象还是很有趣&#xff0c;仔细观察了下&#xff0c;默认的切换顺序是按照控件拖入顺序&#xff0c;那么知道了这个问题想要解决起来就很简…

Linux系统编程学习 NO.10——进程的概念(1)

前言 本篇文章主要了解进程的概念。 #j 冯诺依曼体系结构 什么是冯诺依曼体系结构&#xff1f; 冯诺伊曼体系结构是计算机体系结构的一种经典范式&#xff0c;由计算机科学家约翰冯诺伊曼&#xff08;John von Neumann&#xff09;提出。该体系结构在计算机设计中起到了重要…

如何查看局域网内的浏览记录?总结五种方法,按步操作!一学就会!「管理小白须知」

如何查看局域网内的浏览记录&#xff1f; 你是否也曾为如何有效监控局域网内的浏览记录而苦恼&#xff1f; 监控局域网内电脑的浏览记录是确保员工工作效率、维护网络安全以及规范上网行为的重要手段。 别担心&#xff0c;今天我们就来聊聊这个话题&#xff0c;为你揭秘五种简…

室内场景建筑构成和常见物品识别图像分割系统:完整教学

室内场景建筑构成和常见物品识别图像分割系统源码&#xff06;数据集分享 [yolov8-seg-p6&#xff06;yolov8-seg-fasternet等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来…

前端vue3若依框架pnpm run dev启动报错

今天前端vue3若依框架pnpm run dev启动报错信息&#xff1a; > ruoyi3.8.8 dev D:\AYunShe\2024-11-6【无锡出门证】\wuxi-exit-permit-web > vite error when starting dev server: Error: listen EACCES: permission denied 0.0.0.0:80 at Server.setupListenHand…

nacos — 动态路由

Nacos 是一个阿里巴巴开源的服务注册中心&#xff0c;广泛用于微服务架构中。它除了支持服务注册和配置管理外&#xff0c;还可以配合网关实现动态路由。动态路由能够根据配置的实时更新动态调整路由规则&#xff0c;避免应用重启&#xff0c;实现路由的灵活管理。 网关的路由…

排序 (插入/选择排序)

目录 一 . 排序概念及运用 1.1 排序的概念 1.2 排序的应用 1.3 常见的排序算法 二 . 插入排序 2.1 直接插入排序 2.1 复杂度分析 2.3 希尔排序 2.4 希尔排序时间复杂度分析 三 . 选择排序 3.1 直接选择排序 3.2 堆排序 一 . 排序概念及运用 1.1 排序的概念 排序 : 所…

Unity网络开发基础(part5.网络协议)

目录 前言 网络协议概述 OSI模型 OSI模型的规则 第一部分 物理层 数据链路层 网络层 传输层 第二部分 ​编辑 应用层 表示层 会话层 每层的职能 TCP/IP协议 TCP/IP协议的规则 TCP/IP协议每层的职能 TCP/IP协议中的重要协议 TCP协议 三次握手 四次挥手 U…

框架学习01-Spring

一、Spring框架概述 Spring是一个开源的轻量级Java开发框架&#xff0c;它的主要目的是为了简化企业级应用程序的开发。它提供了一系列的功能&#xff0c;包括控制反转&#xff08;IOC&#xff09;、注入&#xff08;DI&#xff09;、面向切面编程&#xff08;AOP&#xff09;…

Late Chunking×Milvus:如何提高RAG准确率

01. 背景 在RAG应用开发中&#xff0c;第一步就是对于文档进行chunking&#xff08;分块&#xff09;&#xff0c;高效的文档分块&#xff0c;可以有效的提高后续的召回内容的准确性。而对于如何高效的分块是个讨论的热点&#xff0c;有诸如固定大小分块&#xff0c;随机大小分…

【深度学习】InstantIR:图片高清化修复

InstantIR——借助即时生成参考的盲图像修复新方法 作者:Jen-Yuan Huang 等 近年来,随着深度学习和计算机视觉技术的飞速发展,图像修复技术取得了令人瞩目的进步。然而,对于未知或复杂退化的图像进行修复,仍然是一个充满挑战的任务。针对这一难题,研究者们提出了 Insta…

qt获取本机IP和定位

前言&#xff1a; 在写一个天气预报模块时&#xff0c;需要一个定位功能&#xff0c;在网上翻来翻去才找着&#xff0c;放在这里留着回顾下&#xff0c;也帮下有需要的人 正文&#xff1a; 一开始我想着直接调用百度地图的API来定位&#xff0c; 然后我就想先获取本机IP的方…

(C++回溯算法)微信小程序“开局托儿所”游戏

问题描述 给定一个矩阵 A ( a i j ) m n \bm A(a_{ij})_{m\times n} A(aij​)mn​&#xff0c;其中 a i j ∈ { 1 , 2 , ⋯ , 9 } a_{ij}\in\{1,2,\cdots,9\} aij​∈{1,2,⋯,9}&#xff0c;且满足 ∑ i 1 m ∑ j 1 n a i j \sum\limits_{i1}^m\sum\limits_{j1}^na_{ij} i…

数字隔离器与光隔离器有何不同?---腾恩科技

在电子隔离中&#xff0c;两种常用的解决方案是数字隔离器和光学隔离器。两者都旨在电气隔离电路的各个部分&#xff0c;以保护敏感元件免受高压干扰&#xff0c;但它们通过不同的技术实现这一目标。本文探讨了这些隔离器之间的差异&#xff0c;重点介绍了它们的工作原理、优势…

什么是多因素身份验证(MFA)的安全性?

多因素身份验证(MFA)简介 什么是MFA 多因素身份验证(MFA)是一种安全过程&#xff0c;要求用户在授予对系统、应用程序或账户的访问权限之前提供两种或多种形式的验证。仅使用单个因素&#xff08;通常是用户名和密码&#xff09;保护资源会使它们容易受到泄露&#xff0c;添加…

10天进阶webpack---(2)webpack模块兼容性处理

回顾CMJ和ESM的区别 CMJ的本质可以使用一个函数概括 // require函数的伪代码 function require(path){if(该模块有缓存吗){return 缓存结果;}function _run(exports, require, module, __filename, __dirname){// 模块代码会放到这里}var module {exports: {}}_run.call(mod…