Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】
Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】
目录
Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】
一、简单介绍
二、状态模式(State Pattern)
1、什么时候使用状态模式
2、使用状态模式的好处
3、使用状态模式时的注意事项
三、在 Unity 中使用 状态模式
1、定义状态接口
2、具体状态类
3、上下文类
4、使用场景中的角色
5、在 Unity 中运行
6、示例分析
四、观察者模式(Observer Pattern)
1、什么时候使用观察者模式
2、使用观察者模式的好处
3、使用时的注意事项
五、在 Unity 中使用 观察者模式
1、定义观察者接口
2、定义被观察者类
3、实现观察者类
4、在场景中使用观察者模式
5、运行示例
6、示例分析
六、备忘录模式(Memento Pattern)
1、什么时候使用备忘录模式
2、使用备忘录模式的好处
3、使用时的注意事项
七、在 Unity 中使用 备忘录模式
1、定义备忘录类
2、定义发起人类
3、定义管理员类
4、在 Unity 中测试
5、运行示例
6、示例分析
一、简单介绍
设计模式 是指在软件开发中为解决常见问题而总结出的一套 可复用的解决方案。这些模式是经过长期实践证明有效的 编程经验总结,并可以在不同的项目中复用。设计模式并不是代码片段,而是对常见问题的 抽象解决方案,它提供了代码结构和模块间交互的一种设计思路,帮助开发者解决特定的设计问题。
设计模式的特点:
- 通用性:设计模式针对的是软件开发中常见的设计问题,适用于各种软件工程项目。
- 可复用性:设计模式可以在不同项目和环境下被重复使用,提高代码的可维护性和扩展性。
- 可扩展性:设计模式有助于让代码结构更加灵活,易于扩展和修改。
- 模块化:通过设计模式,可以减少代码的耦合性,增强模块间的独立性。
- 提高沟通效率:设计模式为开发者提供了一种通用的设计语言,使得团队成员能够快速理解并讨论设计方案。
二、状态模式(State Pattern)
状态模式(State Pattern) 是一种行为型设计模式,它允许一个对象在其内部状态发生改变时改变其行为。状态模式将与状态相关的行为封装在独立的状态类中,系统在运行时根据状态的变化来切换不同的行为。
通过状态模式,状态转换和行为执行得到了很好的分离,符合面向对象设计的单一职责原则,即每个类只负责一项具体的职责。
状态模式的结构
- 上下文类(Context Class):维护当前状态的引用,负责在运行时根据状态的变化调用不同的状态类的行为。
- 状态接口(State Interface):定义状态类的共同行为,这通常是一个抽象类或接口。
- 具体状态类(Concrete State Class):实现状态接口,提供每个状态下具体的行为。
1、什么时候使用状态模式
-
对象的行为依赖于状态变化时,并且行为会随着状态的不同而发生变化。
-
对象的状态变化频繁,而且状态之间的切换逻辑复杂,状态模式可以很好地管理这些状态。
-
状态转换具有规律性,每个状态都有固定的行为模式或规则,状态模式可以简化这种逻辑。
-
需要避免使用大量条件判断来实现不同状态下的行为时,状态模式是一个更优雅的解决方案。
2、使用状态模式的好处
-
简化条件判断逻辑:通过将状态转换逻辑封装到各个具体状态类中,状态模式避免了大量的
if-else
或switch
语句,代码更清晰。 -
增强系统的扩展性:状态模式将状态相关的行为封装到独立的类中,因此添加新的状态或修改现有状态的行为不会影响其他代码,符合开闭原则。
-
使状态行为与上下文解耦:上下文类仅负责状态的切换,而具体的行为由状态类来实现,保持了上下文类的简洁。
-
提高代码可维护性:状态类各自独立,便于测试、调试和维护。
3、使用状态模式时的注意事项
-
状态类的数量增加:状态模式的一个潜在问题是状态类的数量可能会随着状态的增多而增加,导致类过多。此时需要评估是否有必要使用状态模式,还是可以通过其他方式优化。
-
上下文和状态类的依赖:虽然状态模式将状态行为独立出来,但状态类与上下文之间的相互引用可能导致依赖复杂性,需要控制好状态类的职责。
-
状态转换规则复杂时:如果状态之间的转换规则非常复杂,可能需要将转换逻辑从具体状态类中抽离,避免具体状态类中的代码变得过于庞大。
三、在 Unity 中使用 状态模式
在 Unity 中,状态模式可以很好地用于角色的状态管理,例如角色的运动状态、攻击状态、死亡状态等。我们可以通过状态模式将这些行为封装在不同的状态类中,使得角色能够根据当前状态动态切换行为。
下面我们使用状态模式,实现一个角色可以在站立、行走、奔跑和跳跃状态之间切换的示例,基于 Unity 的 3D 环境。
参考类图如下:
1、定义状态接口
我们首先定义一个接口 ICharacterState
,每个具体的状态类都需要实现该接口。
public interface ICharacterState
{void HandleInput(Character character);void UpdateState(Character character);
}
2、具体状态类
根据不同的角色状态(站立、行走、奔跑、跳跃),我们为每个状态创建一个具体的类。每个状态类都实现了 ICharacterState
接口。
using UnityEngine;// 站立状态类
public class StandState : ICharacterState
{public void HandleInput(Character character){if (Input.GetKeyDown(KeyCode.W)){character.SetState(new WalkState());}}public void UpdateState(Character character){Debug.Log("角色正在站立");}
}// 行走状态类
public class WalkState : ICharacterState
{public void HandleInput(Character character){if (Input.GetKeyDown(KeyCode.R)){character.SetState(new RunState());}else if (Input.GetKeyDown(KeyCode.Space)){character.SetState(new JumpState());}}public void UpdateState(Character character){character.transform.Translate(Vector3.forward * 2f * Time.deltaTime);Debug.Log("角色正在行走");}
}// 奔跑状态类
public class RunState : ICharacterState
{public void HandleInput(Character character){if (Input.GetKeyDown(KeyCode.Space)){character.SetState(new JumpState());}}public void UpdateState(Character character){character.transform.Translate(Vector3.forward * 5f * Time.deltaTime);Debug.Log("角色正在奔跑");}
}// 跳跃状态类
public class JumpState : ICharacterState
{public void HandleInput(Character character){// 空中不允许其他输入}public void UpdateState(Character character){character.transform.Translate(Vector3.up * 5f * Time.deltaTime);Debug.Log("角色正在跳跃");// 跳跃结束后返回站立状态character.SetState(new StandState());}
}
3、上下文类
接下来定义上下文类 Character
,它维护当前的状态,并通过 SetState()
方法进行状态的切换。
using UnityEngine;public class Character : MonoBehaviour
{private ICharacterState currentState;void Start(){// 初始化状态为站立currentState = new StandState();}void Update(){// 处理输入并更新状态currentState.HandleInput(this);currentState.UpdateState(this);}// 切换状态public void SetState(ICharacterState newState){currentState = newState;}
}
4、使用场景中的角色
在 Unity 场景中,我们可以将此状态系统应用到一个角色对象上,比如一个 3D 模型。使用状态模式,角色将根据输入切换行为,比如从站立到行走,再到奔跑或跳跃。
创建一个新的脚本 GameController
来管理和初始化角色。
using UnityEngine;public class GameController : MonoBehaviour
{public GameObject characterPrefab;private Character character;void Start(){// 初始化角色对象GameObject characterObject = Instantiate(characterPrefab);character = characterObject.AddComponent<Character>();}}
5、在 Unity 中运行
- 创建一个空的 Unity 场景,放置一个 3D 角色(立方体、模型等)作为
characterPrefab
。 - 添加
Character
和GameController
脚本到 Unity 场景。 - 在游戏运行时,角色会根据键盘输入(
W
切换到行走状态,R
切换到奔跑状态,空格键切换到跳跃状态)来切换不同的行为。
6、示例分析
- 初始状态为站立:当游戏开始时,角色默认处于站立状态。此时控制台输出“角色正在站立”,并且没有移动。
- 切换到行走状态:当玩家按下
W
键时,角色进入行走状态,角色开始向前移动,控制台输出“角色正在行走”。 - 切换到奔跑状态:按下
R
键,角色从行走状态切换到奔跑状态,移动速度加快,控制台输出“角色正在奔跑”。 - 切换到跳跃状态:按下空格键,角色进入跳跃状态,角色向上移动,跳跃结束后角色自动返回站立状态。
状态模式在 Unity 中非常适用于处理角色的状态转换。例如,角色的运动状态、游戏中的敌人 AI 状态等。通过将每个状态的行为封装成独立的类,我们可以灵活地进行状态切换并保持代码结构的清晰与可扩展性。
- 简化了复杂的状态管理:避免使用大量的
if-else
或switch-case
语句,减少了冗余代码。- 高可扩展性:当需要添加新的状态时,只需要新建一个状态类即可,不会影响现有的代码。
- 增强了代码的可维护性:各个状态之间相互独立,符合单一职责原则,每个状态类只负责处理特定状态下的行为。
四、观察者模式(Observer Pattern)
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系。当一个对象的状态发生变化时,它的所有依赖者(观察者)都会收到通知并自动更新。这种模式用于事件处理系统,当某个对象发生改变时,依赖该对象的其他对象能够及时响应。
在观察者模式中,主要有两个角色:
- 被观察者(Subject):状态发生变化的对象,它维护了一组观察者列表,并在状态发生变化时通知它们。
- 观察者(Observer):依赖被观察者的对象,它注册到被观察者上,并在被观察者状态变化时得到通知。
1、什么时候使用观察者模式
- 事件系统:需要实现基于事件驱动的系统,许多 UI 系统使用观察者模式来处理按钮点击、值变化等事件。
- 数据同步:当某个对象的状态改变时,依赖它的其他对象需要同步更新。
- 系统中存在一对多的依赖关系:例如,一个对象的变化需要通知多个对象做出反应,典型的例子包括股票价格变化通知、新闻订阅系统等。
- 通知机制:在某些情况下,多个模块需要接收到某个变化的信息(如游戏事件、社交媒体通知等)。
2、使用观察者模式的好处
- 解耦合:观察者和被观察者之间的耦合度低。被观察者只知道观察者实现了某些接口,而无需了解它们的具体实现细节。
- 灵活性:可以动态添加或移除观察者,系统的扩展性好。
- 提高代码的可维护性:将状态的变化与相应的反应分开,使代码更易于维护和修改。
- 响应式更新:观察者模式允许系统中的多个对象自动响应某个对象的状态变化,无需显式调用每个依赖对象。
3、使用时的注意事项
- 性能问题:当观察者数量过多时,每次状态改变都需要通知所有观察者,这可能会引起性能问题。
- 避免循环依赖:如果观察者在更新过程中再次触发了被观察者的通知,可能会导致循环调用或死锁。
- 顺序问题:多个观察者对同一事件做出响应时,要注意观察者之间的顺序依赖,可能会导致某些观察者未按预期更新。
- 内存泄漏问题:要确保观察者可以正确地从被观察者中移除,以避免内存泄漏问题。
五、在 Unity 中使用 观察者模式
为了演示如何在 Unity 中使用 观察者模式,我们将实现一个示例:当玩家接触到一个触发器(Trigger)时,游戏会通知观察者更新,例如改变颜色、显示文本等。这个示例将演示如何使用观察者模式管理多个对象对玩家触发事件做出反应。
参考类图如下:
1、定义观察者接口
首先,我们定义一个观察者接口,所有的观察者类都需要实现这个接口。
public interface IObserver
{void OnNotify();
}
2、定义被观察者类
然后我们定义一个被观察者类。在这个示例中,被观察者是一个触发器,当玩家接触触发器时,它会通知所有观察者。
using System.Collections.Generic;
using UnityEngine;public class TriggerSubject : MonoBehaviour
{private List<IObserver> observers = new List<IObserver>();// 注册观察者public void RegisterObserver(IObserver observer){observers.Add(observer);}// 移除观察者public void RemoveObserver(IObserver observer){observers.Remove(observer);}// 通知所有观察者public void NotifyObservers(){foreach (IObserver observer in observers){observer.OnNotify();}}// Unity 的触发器事件,当玩家接触触发器时调用private void OnTriggerEnter(Collider other){if (other.CompareTag("Player")){NotifyObservers();}}
}
3、实现观察者类
接下来我们创建几个不同的观察者类,每个观察者类会响应触发器的通知。在这个例子中,我们将创建两个观察者:
- 一个会改变颜色
- 一个会显示文本
3.1 观察者 1:改变颜色的观察者
using UnityEngine;public class ColorObserver : MonoBehaviour, IObserver
{public Renderer objectRenderer;public void OnNotify(){// 随机改变对象的颜色objectRenderer.material.color = new Color(Random.value, Random.value, Random.value);Debug.Log("ColorObserver: Color changed!");}
}
3.2 观察者 2:显示文本的观察者
using UnityEngine;
using UnityEngine.UI;public class TextObserver : MonoBehaviour, IObserver
{public Text messageText;public void OnNotify(){// 显示通知文本messageText.text = "Player triggered the event!";Debug.Log("TextObserver: Text updated!");}
}
4、在场景中使用观察者模式
现在我们在 Unity 场景中设置以下内容:
-
创建一个空的 GameObject,命名为 Trigger,并将
TriggerSubject
脚本附加到该对象上。同时,在该对象上添加一个 BoxCollider,并勾选 Is Trigger。 -
创建两个 3D 物体(如立方体或球体),并附加
ColorObserver
脚本到其中一个物体,记得将objectRenderer
变量拖入到 Inspector 中。 -
创建一个 UI 文本,附加
TextObserver
脚本,并将messageText
变量拖入 Inspector。 -
在游戏的
Start()
函数中,注册观察者。
using UnityEngine;public class GameManager : MonoBehaviour
{public TriggerSubject triggerSubject;public ColorObserver colorObserver;public TextObserver textObserver;void Start(){// 注册观察者triggerSubject.RegisterObserver(colorObserver);triggerSubject.RegisterObserver(textObserver);}void OnDestroy(){// 在销毁时移除观察者,避免内存泄漏triggerSubject.RemoveObserver(colorObserver);triggerSubject.RemoveObserver(textObserver);}
}
5、运行示例
- 将
GameManager
脚本挂载到 Unity 场景中的一个空对象上。 - 在
GameManager
中的Inspector
窗口,将triggerSubject
、colorObserver
和textObserver
分别拖入相应的字段。 - 运行游戏,当玩家接触
Trigger
对象时,注册的观察者将会被通知:- 物体的颜色会发生变化。
- UI 文本会显示 "Player triggered the event!"。
6、示例分析
- 触发器 (
TriggerSubject
) 是被观察者,当玩家接触它时,它会调用NotifyObservers()
方法通知所有的观察者。 - 观察者 (
ColorObserver
和TextObserver
) 实现了IObserver
接口,并在OnNotify()
方法中定义了各自的行为。 - 通过这种设计,任何新增的观察者只需要实现
IObserver
接口,并注册到TriggerSubject
中,而不需要修改已有的代码。
通过这个示例,我们可以看到如何在 Unity 中运用 观察者模式,处理多个对象对同一事件的响应。这种模式在处理游戏事件、状态变化等场景中十分有用,尤其是在复杂的游戏系统中。
- 松耦合:观察者和被观察者之间的关系松耦合,被观察者不需要关心观察者的具体实现。
- 扩展性:可以轻松添加新的观察者,而无需修改被观察者的代码。
六、备忘录模式(Memento Pattern)
备忘录模式(Memento Pattern)是一种行为型设计模式,它允许在不暴露对象内部状态的情况下保存和恢复对象的状态。备忘录模式通常用于需要撤销或恢复操作的场景。模式主要由三个角色组成:
- 发起人(Originator):需要保存和恢复状态的对象。
- 备忘录(Memento):保存发起人的内部状态的对象。
- 管理员(Caretaker):负责管理备忘录的对象,它不对备忘录的内容进行操作,只负责保存和恢复。
1、什么时候使用备忘录模式
- 撤销操作:当用户需要撤销某个操作,例如文本编辑器中的撤销/重做功能。
- 游戏存档:在游戏中保存和恢复玩家的状态,例如关卡进度、角色状态等。
- 复杂状态管理:当对象的状态比较复杂,且需要频繁保存和恢复时。
2、使用备忘录模式的好处
- 封装性:备忘录模式允许保存对象的状态,而无需暴露其内部结构。
- 简化状态管理:可以轻松地实现状态的保存和恢复,尤其是在需要实现撤销/重做功能时。
- 易于实现:对于需要保留状态的对象,备忘录模式提供了一种简单、直观的方式来管理对象的状态。
3、使用时的注意事项
- 内存使用:备忘录模式可能会消耗大量内存,特别是在需要保存大量状态时。需要合理管理备忘录的数量。
- 性能问题:频繁的状态保存和恢复可能会影响系统性能。
- 设计复杂性:虽然备忘录模式提供了良好的封装性,但实现可能会增加系统的复杂性。
七、在 Unity 中使用 备忘录模式
为了在 Unity 中演示 备忘录模式,我们将实现一个简单的示例:玩家可以在场景中移动,并能够保存和恢复其位置和生命值的状态。这个示例将展示如何使用备忘录模式管理游戏状态。
参考类图如下:
1、定义备忘录类
首先,我们定义一个备忘录类,用于保存玩家的状态信息(位置和生命值)。
[System.Serializable]
public class PlayerMemento
{public Vector3 position;public int health;public PlayerMemento(Vector3 position, int health){this.position = position;this.health = health;}
}
2、定义发起人类
接下来,我们定义一个 Player
类,它代表玩家,并提供保存和恢复状态的方法。
using UnityEngine;public class Player : MonoBehaviour
{public Vector3 position;public int health;void Start(){position = transform.position; // 初始化位置health = 100; // 初始化生命值}// 创建备忘录public PlayerMemento CreateMemento(){return new PlayerMemento(position, health);}// 从备忘录恢复状态public void RestoreMemento(PlayerMemento memento){position = memento.position;health = memento.health;transform.position = position; // 更新实际位置}void Update(){// 移动玩家float moveSpeed = 5f;float moveHorizontal = Input.GetAxis("Horizontal");float moveVertical = Input.GetAxis("Vertical");Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical) * moveSpeed * Time.deltaTime;transform.Translate(movement);// 打印当前状态if (Input.GetKeyDown(KeyCode.Space)){Debug.Log($"Current Position: {transform.position}, Health: {health}");}}// 示例:改变生命值public void TakeDamage(int damage){health -= damage;Debug.Log($"Player took damage: {damage}. Current Health: {health}");}
}
3、定义管理员类
然后,我们定义一个 GameManager
类,用于管理备忘录的保存和恢复。
using System.Collections.Generic;
using UnityEngine;public class GameManager : MonoBehaviour
{private Player player;private List<PlayerMemento> mementoList = new List<PlayerMemento>();private int currentStateIndex = -1;void Start(){player = FindObjectOfType<Player>();}// 保存当前状态public void SaveState(){PlayerMemento memento = player.CreateMemento();mementoList.Add(memento);currentStateIndex++;Debug.Log($"Game state saved! Total states: {mementoList.Count}");}// 恢复到上一个状态public void RestorePreviousState(){if (currentStateIndex > 0){currentStateIndex--;player.RestoreMemento(mementoList[currentStateIndex]);Debug.Log($"Restored to state {currentStateIndex}!");}else{Debug.Log("No previous state to restore!");}}// 恢复到下一个状态public void RestoreNextState(){if (currentStateIndex < mementoList.Count - 1){currentStateIndex++;player.RestoreMemento(mementoList[currentStateIndex]);Debug.Log($"Restored to state {currentStateIndex}!");}else{Debug.Log("No next state to restore!");}}void Update(){if (Input.GetKeyDown(KeyCode.S)) // 按下 S 保存状态{SaveState();}if (Input.GetKeyDown(KeyCode.R)) // 按下 R 恢复上一个状态{RestorePreviousState();}if (Input.GetKeyDown(KeyCode.N)) // 按下 N 恢复下一个状态{RestoreNextState();}if (Input.GetKeyDown(KeyCode.D)) // 按下 D 造成伤害{player.TakeDamage(10);}}
}
4、在 Unity 中测试
- 创建一个空的 GameObject,命名为 GameManager,并附加
GameManager
脚本。 - 创建一个球体作为玩家对象,附加
Player
脚本。 - 在 Unity 编辑器中,设置场景,确保玩家对象和游戏管理器在同一场景中。
5、运行示例
在游戏运行时,玩家可以使用以下键来测试备忘录模式:
- S:保存当前状态。
- R:恢复到上一个保存的状态。
- N:恢复到下一个保存的状态。
- D:造成 10 点伤害(测试生命值变化)。
6、示例分析
- 发起人(Player):玩家的状态可以被保存和恢复。
CreateMemento()
方法创建备忘录,RestoreMemento()
方法从备忘录恢复状态。 - 备忘录(PlayerMemento):封装了玩家的位置和生命值。
- 管理员(GameManager):管理备忘录,允许保存和恢复状态。
通过这个示例,我们展示了如何在 Unity 中实现 备忘录模式,用于管理对象的状态保存和恢复。这种模式在处理游戏中的撤销/重做功能、存档等场景中非常有用。
- 状态管理简单:通过备忘录模式,可以轻松保存和恢复玩家的状态。
- 封装性强:玩家的内部状态不暴露,保持了良好的封装性。
- 灵活性:可以方便地扩展状态保存的内容,例如增加更多的属性。
相关文章:

Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】
Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】 目录 Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】 一、简单介绍 二、状态模式(State Pattern) 1、什么时候使用状态模式 2、使用状态模式的…...

【RabbitMQ】RabbitMQ 的概念以及使用RabbitMQ编写生产者消费者代码
目录 1. RabbitMQ 核心概念 1.1生产者和消费者 1.2 Connection和Channel 1.3 Virtual host 1.4 Queue 1.5 Exchange 1.6 RabbitMO工作流程 2. AMQP 3.RabbitMO快速入门 3.1.引入依赖 3.2.编写生产者代码 3.3.编写消费者代码 4.源码 1. RabbitMQ 核心概念 在安装…...

openmv与stm32通信
控制小车视觉循迹使用 OpenMV 往往是不够的。一般使用 OpenMV 对图像进行处理,将处理过后的数据使用串口发送给STM32,使用STM32控制小车行驶。本文主要讲解 OpenMV 模块与 STM32 间的串口通信以及两种循迹方案,分别是划分检测区域和线性回归。…...

C++ STL全面解析:六大核心组件之一----序列式容器(vector和List)(STL进阶学习)
目录 序列式容器 Vector vector概述 vector的迭代器 vector的数据结构 vector的构造和内存管理 vector的元素操作 List List概述 List的设计结构 List的迭代器 List的数据结构 List的内存构造 List的元素操作 C标准模板库(STL)是一组高效的…...

【c数据结构】OJ练习篇 帮你更深层次理解链表!(相交链表、相交链表、环形链表、环形链表之寻找环形入口点、判断链表是否是回文结构、 随机链表的复制)
目录 一. 相交链表 二. 环形链表 三. 环形链表之寻找环形入口点 四. 判断链表是否是回文结构 五. 随机链表的复制 一. 相交链表 最简单粗暴的思路,遍历两个链表,分别寻找是否有相同的对应的结点。 我们对两个链表的每个对应的节点进行判断比较&…...

微软开源GraphRAG的使用教程(最全,非常详细)
GraphRAG的介绍 目前微软已经开源了GraphRAG的完整项目代码。对于某一些LLM的下游任务则可以使用GraphRAG去增强自己业务的RAG的表现。项目给出了两种使用方式: 在打包好的项目状态下运行,可进行尝试使用。在源码基础上运行,适合为了下游任…...

使用Refine构建项目(1)初始化项目
要初始化一个空的Refine项目,你可以使用Refine提供的CLI工具create-refine-app。以下是初始化步骤: 使用npx命令: 在命令行中运行以下命令来创建一个新的Refine项目: npx create-refine-applatest my-refine-project这将引导你通过…...

【Docker】安装及使用
1. 安装Docker Desktop Docker Desktop是官方提供的桌面版Docker客户端,在Mac上使用Docker需要安装这个工具。 访问 Docker官方页面 并下载Docker Desktop for Mac。打开下载的.dmg文件,并拖动Docker图标到应用程序文件夹。安装完成后,打开…...

[大语言模型-论文精读] 以《黑神话:悟空》为研究案例探讨VLMs能否玩动作角色扮演游戏?
1. 论文简介 论文《Can VLMs Play Action Role-Playing Games? Take Black Myth Wukong as a Study Case》是阿里巴巴集团的Peng Chen、Pi Bu、Jun Song和Yuan Gao,在2024.09.19提交到arXiv上的研究论文。 论文: https://arxiv.org/abs/2409.12889代码和数据: h…...

提升动态数据查询效率:应对数据库成为性能瓶颈的优化方案
引言 在现代软件系统中,数据库性能是决定整个系统响应速度和处理能力的关键因素之一。然而,当系统负载增加,特别是在高并发、大数据量场景下,数据库性能往往会成为瓶颈,导致查询响应时间延长,影响用户体验…...

Prometheus+grafana+kafka_exporter监控kafka运行情况
使用Prometheus、Grafana和kafka_exporter来监控Kafka的运行情况是一种常见且有效的方案。以下是详细的步骤和说明: 1. 部署kafka_exporter 步骤: 从GitHub下载kafka_exporter的最新版本:kafka_exporter项目地址(注意ÿ…...

在vue中:style 的几种使用方式
在日常开发中:style的使用也是比较常见的: 亲测有效 1.最通用的写法 <p :style"{fontFamily:arr.conFontFamily,color:arr.conFontColor,backgroundColor:arr.conBgColor}">{{con.title}}</p> 2.三元表达式 <a :style"{height:…...

商城小程序后端开发实践中出现的问题及其解决方法
前言 商城小程序后端开发中,开发者可能会面临多种问题。以下是一些常见的问题及其解决方法: 一、性能优化 问题:随着用户量的增加和功能的扩展,商城小程序可能会出现响应速度慢、处理效率低的问题。 解决方法: 对数…...

阿里Arthas-Java诊断工具,基本操作和命令使用
Arthas 是阿里巴巴开源的一款Java诊断工具,深受开发者喜爱。它可以帮助开发者在不需要修改代码的情况下,对运行中的Java程序进行问题诊断和性能分析。 软件具体使用方法 1 启动 Arthas,此时可能会出现好几个jvm的进程号,输入序号…...

Go 1.19.4 路径和目录-Day 15
1. 路径介绍 存储设备保存着数据,但是得有一种方便的模式让用户可以定位资源位置,操作系统采用一种路径字符 串的表达方式,这是一棵倒置的层级目录树,从根开始。 相对路径:不是以根目录开始的路径,例如 a/b…...

jEasyUI 创建标签页
jEasyUI 创建标签页 jEasyUI(jQuery EasyUI)是一个基于jQuery的框架,它为Web应用程序提供了丰富的用户界面组件。标签页(Tabs)是jEasyUI中的一个常用组件,用于在一个页面内组织多个面板,用户可…...

鸿蒙HarmonyOS开发:一次开发,多端部署(界面级)天气应用案例
文章目录 一、布局简介二、典型布局场景三、侧边栏 SideBarContainer1、子组件2、属性3、事件 四、案例 天气应用1、UX设计2、实现分析3、主页整体实现4、具体代码 五、运行效果 一、布局简介 布局可以分为自适应布局和响应式布局,二者的介绍如下表所示。 名称简介…...

使用 Python 模拟光的折射,反射,和全反射
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

大厂太卷了!又一款国产AI视频工具上线了,免费无限使用!(附提示词宝典)
大家好,我是程序员X小鹿,前互联网大厂程序员,自由职业2年,也一名 AIGC 爱好者,持续分享更多前沿的「AI 工具」和「AI副业玩法」,欢迎一起交流~ 记得去年刚开始分享 AI 视频工具的时候,介绍的大多…...

vue3扩展echart封装为组件库-快速复用
ECharts ECharts,全称Enterprise Charts,是一款由百度团队开发并开源,后捐赠给Apache基金会的纯JavaScript图表库。它提供了直观、生动、可交互、可个性化定制的数据可视化图表,广泛应用于数据分析、商业智能、网页开发等领域。以…...

随机掉落的项目足迹:Vue3 + wangEditor5富文本编辑器——toolbar.getConfig() 查看工具栏的默认配置
问题引入 小提示:问题引入是一个讲故事的废话环节,各位小伙伴可以直接跳到第二大点:问题解决 我的项目不需要在富文本编辑器中引入添加代码块的功能,于是我寻思在工具栏上把操作代码的菜单删一删 于是我来到官网文档工具栏配置 …...

更新 Git 软件
更新 Git 软件本身是指将你当前安装的 Git 版本升级到最新版本。不同的操作系统有不同的更新方法。以下是针对 Windows、macOS 和 Linux 的 Git 更新步骤: Windows 检查当前版本: git --version访问官网下载最新版本: 访问 Git 官方网站 (ht…...

Keil根据map文件确定单片机代码存储占用flash情况
可以从map文件中查看得知,代码占用内存情况大概为35KB,而在在线仿真时,可以看到在flash的0x8008F64地址前均有数据,是代码数据,8F64(HEX)36708(DEC),36708/102335,刚好35。因此,要想操作读写flash,必须在不…...

ByteTrack多目标跟踪流程图
ByteTrack多目标跟踪流程图 点个赞吧,谢谢。...

什么是L2范数
定义: 在数学和计算中,L2 范数是一种用于测量向量长度或大小的方法,也被称为欧几里得范数。对于一个 n 维向量 x ( x 1 , x 2 , … , x n ) \mathbf{x} (x_1, x_2, \dots, x_n) x(x1,x2,…,xn),其 L2 范数定义为&#x…...

Scrapy爬虫IP代理池:提升爬取效率与稳定性
在互联网时代,数据就是新的黄金。无论是企业还是个人,数据的获取和分析能力都显得尤为重要。而在众多数据获取手段中,使用爬虫技术无疑是一种高效且广泛应用的方法。然而,爬虫在实际操作中常常会遇到IP被封禁的问题。为了解决这个…...

信息技术(IT)行业的发展
近年来,信息技术(IT)行业的发展呈现出前所未有的活力和潜力。随着全球数字化转型的加速,IT行业正逐步成为推动社会经济发展的重要引擎。无论是互联网、大数据、人工智能,还是云计算、物联网,这些新兴技术都…...

C++primer第十一章使用类(矢量随机游走实例)
操作符重载 操作符重载(operator overoading)是一种形式的 C多态。 第8章介绍了C是如何使用户能够定义多个名称相同但特征标(参数列表)不同的函数的。这被称为函数重载(function overloading)或函数多态(functional polymorphism),旨在让您能够用同名的函数来完成…...

服务器为什么会受到网络攻击?
随着科技的 快速发展,企业也开展了越来越多的线上业务,但同时也遭受到各种各样的网络攻击,那服务器为什么会受到网络攻击呢?下面就让小编带领大家一起来了解一下吧! 首先企业中服务器被攻击的原因有很多,主…...

IDA Pro基本使用
IDA Pro基本使用 1.DllMain的地址是什么? 打开默认在的位置1000D02E就是DllMain地址 按空格键可以看到图形化界面选择options、general勾选对应的选项在图像化也能看到 2.使用Imports 窗口并浏览到 gethostbyname,导入函数定位到什么地址? 这里可以打开Impo…...