《学Unity的猫》——第十三章:Unity使用Animator控制动画播放,皮皮猫打字机游戏

本文主要是介绍《学Unity的猫》——第十三章:Unity使用Animator控制动画播放,皮皮猫打字机游戏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

        • 13.1 皮皮猫打字机游戏
        • 13.2 场景制作
          • 13.2.1 入口场景
          • 13.2.2 游戏场景
          • 13.2.3 场景切换
        • 13.3 游戏管理器
          • 13.3.1 数据定义
          • 13.3.2 生成字母盘
          • 13.3.3 按键判断
          • 13.3.4 连击定时器
        • 13.4 动画控制器Animator
          • 13.4.1 添加Animator
          • 13.4.2 Animator状态机
            • 13.4.2.1 Any State状态
            • 13.4.2.2 Entry状态
            • 13.4.2.3 Exit状态
          • 13.4.3 动画状态的属性
          • 13.4.4 状态间的过渡关系(Transitions)
          • 13.4.5 添加状态控制参数
          • 13.4.6 编辑切换状态的条件
        • 13.5 猫娘动画状态机
          • 13.5.1 模型资源下载
          • 13.5.2 动画循环设置
          • 13.5.3 状态过渡设置
        • 13.6 角色动画控制器
          • 13.6.1 数据定义
          • 13.6.2 直接播放动画接口
          • 13.6.3 设置变量值
          • 13.6.4 根据状态队列设置状态
        • 13.7 入口场景脚本
        • 13.8 游戏场景脚本
        • 13.9 文字特效动画

简介:我是一名Unity游戏开发工程师,皮皮是我养的猫,会讲人话,它接到了喵星的特殊任务:学习编程,学习Unity游戏开发。
于是,发生了一系列有趣的故事。
在这里插入图片描述

13.1 皮皮猫打字机游戏

皮皮:“铲屎官,你为什么打字速度这么快?”
我:“一个字,练。”
皮皮:“教教我,怎么连打字速度。”
我:“来,我给你做一个打字练习游戏吧。”
我:“当你可以一分钟连击180次的时候,你就可以出山了。”
皮皮:“作为猫族,不能被速度打败。”
游戏画面如下:
在这里插入图片描述
模块设计如下
在这里插入图片描述

本工程使用的Unity版本为2020.1.14f1c1 (64-bit),工程已上传到GitHub,感兴趣的同学可以下载下来学习。
GitHub地址:https://github.com/linxinfa/Unity-TypeWriting-Game
在这里插入图片描述

13.2 场景制作
13.2.1 入口场景

EntryScene.unity
在这里插入图片描述
在这里插入图片描述
一个标题文本(Text组件),一个开始按钮(Button组件),一个难度选择勾选(ToggleGroupToggle组件)。
背景图使用SpriteRender组件在3D摄像机中渲染。
在这里插入图片描述
难度等级的勾选使用了ToggleGroup组件,用来给Toggle分组。
在这里插入图片描述
子节点中的Toggle需要指明相同的ToggleGroup
在这里插入图片描述
实现单选的效果。
在这里插入图片描述

13.2.2 游戏场景

GameScene.unity
在这里插入图片描述
在这里插入图片描述
一个血条(Slider组件),一个得分(Text组件),一个字母盘(GridLayoutGroupText组件)、一个连击(Text组件),一个角色(SpriteRendererAnimator组件)、一个背景图(SpriteRenderer组件)。
其中字母盘只做一个字母,游戏中进行动态克隆。
在这里插入图片描述
再做游戏结束面板,提供一个返回和重来的按钮。
在这里插入图片描述

13.2.3 场景切换

点击菜单File - Build Settings...
在这里插入图片描述
将场景添加到Scenes In Build中。
在这里插入图片描述
代码中,通过SceneManager.LoadScene切换场景,如下

// 进入GameScene场景
UnityEngine.SceneManagement.SceneManager.LoadScene(1);
13.3 游戏管理器

游戏管理器GameMgr,它需要包括数据和逻辑,如下。
在这里插入图片描述

13.3.1 数据定义
	/// <summary>/// 难度等级/// </summary>public int hardLevel { get; set; }/// <summary>/// 得分/// </summary>public int score { get; set; }/// <summary>/// 最大血量/// </summary>private const int MAX_BLOOD = 1500;/// <summary>/// 血量/// </summary>public int blood{get { return m_blood; }set{m_blood = value;if (m_blood <= 0){gameOver = true;// TODO 抛出事件}}}private int m_blood = 0;/// <summary>/// 连击数量/// </summary>public int comboCnt { get; set; }/// <summary>/// 连击定时器/// </summary>public float comboTimer { get; set; }/// <summary>/// 游戏结束/// </summary>public bool gameOver { get; private set; }/// <summary>/// 按键列表/// </summary>public List<KeyCode> keyList { get { return m_keyList; } }private List<KeyCode> m_keyList = new List<KeyCode>();
13.3.2 生成字母盘

生成字母盘(16个字母),要求每个字母都不重复,生成的字母存到m_keyList中。
在这里插入图片描述

 	/// <summary>/// 生成字母盘/// </summary>private void GenKeys(){for (int i = 0; i < 16; ++i){m_keyList.Add(GenOneKey());}}/// <summary>/// 生成一个字母/// </summary>/// <returns></returns>private KeyCode GenOneKey(){var key = (KeyCode)UnityEngine.Random.Range((int)KeyCode.A, (int)KeyCode.Z);for(int i=0,cnt=m_keyList.Count;i<cnt;++i){if(m_keyList[i] == key){// 如果生成的字母已存在,则递归生成return GenOneKey();}}return key;}
13.3.3 按键判断

我们需要先判断按键类型,封装一个接口GetKeyDownCode

    /// <summary>/// 获取按键类型/// </summary>/// <returns></returns>public KeyCode GetKeyDownCode(){if (Input.anyKeyDown){foreach (KeyCode keyCode in Enum.GetValues(typeof(KeyCode))){if (Input.GetKeyDown(keyCode)){return keyCode;}}}return KeyCode.None;}

然后判断按下的按键是否在字母盘中,返回对应的索引,如果不在字母盘中,则返回-1。

    /// <summary>/// 判断按键是否在字母盘中/// </summary>/// <param name="key">按键</param>/// <returns></returns>private int IsKeyBingo(KeyCode key){for (int i = 0, cnt = m_keyList.Count; i < cnt; ++i){if (m_keyList[i] == key)return i;}return -1;}

按键正确的时候,执行连击计算,加血加分,生成新的字母,抛事件更新ui

    /// <summary>/// 按键正确/// </summary>private void OnKeyBingo(int bingoIndex){// 加连击++comboCnt;if (comboCnt >= 3){// 加血加分,连击加持blood += 150;if (blood > MAX_BLOOD)blood = MAX_BLOOD;score += 20;}else{// 加血加分blood += 50;score += 10;}// 生成新的字母var oldKey = m_keyList[bingoIndex];var newKey = GenOneKey();m_keyList[bingoIndex] = newKey;// TODO 抛事件,更新ui}

按键错误的时候,连击中断,扣血,抛事件更新ui

    /// <summary>/// 按键错误/// </summary>private void OnKeyError(){// 连击中断comboCnt = 0;// 扣血blood -= 30;// TODO 抛事件,更新ui}
13.3.4 连击定时器

如下,其中Time.deltaTime是一帧的间隔时间。每帧调用UpdateComboTimer,对comboTimer进行帧间隔时间递减,通过comboTimer判断是否超过时间限制,超过则中断连击。

    /// <summary>/// 连击定时器/// </summary>public void UpdateComboTimer(){if (comboTimer > 0){comboTimer -= Time.deltaTime;// 超过时间限制,连击断开if (comboTimer <= 0){comboCnt = 0;// TODO 抛事件更新连击ui}}}
13.4 动画控制器Animator

Unity可以用两种方式控制动画
1 Animation,这种方式简单,直接 Play(“Idle”)或者CorssFade(“Idle”)就可以播放动画;
2 AnimatorUnity5.x之后推荐使用这种方式,因为里面可以加上混合动画,让动画切换更加平滑。

13.4.1 添加Animator

点击菜单Window - Animation - Animation,可以打开Animation窗口,快捷键是Ctrl+6
在这里插入图片描述
选中某个物体后,可以为该物体添加或编辑动画,比如选中一个空物体,由于没有动画,会出现一个Create按钮。在这里插入图片描述
点击Create按钮,会弹出窗口设置文件保存路劲。
在这里插入图片描述
创建成功后,物体上会出现一个Animator组件。
在这里插入图片描述

并且我们可以在目录中看到生成了两个文件。
在这里插入图片描述
.controller文件是一个动画状态机,在Unity中双击它会打开Animator窗口,即可看到里面的内容,我们可以在这个窗口中组织各个动画文件。
在这里插入图片描述
.anim是动画文件,在Unity中双击它会打开Animation窗口,我们可以在这个窗口中制作动画。
在这里插入图片描述

13.4.2 Animator状态机

每个Animator Controller都会自带三个状态:Any State, EntryExit
在这里插入图片描述

13.4.2.1 Any State状态

表示任意状态的特殊状态。例如我们如果希望角色在任何状态下都有可能切换到死亡状态,那么Any State就可以帮我们做到。当你发现某个状态可以从任何状态以相同的条件跳转到时,那么你就可以用Any State来简化过渡关系。

13.4.2.2 Entry状态

表示状态机的入口状态。当我们为某个GameObject添加上Animator组件时,这个组件就会开始发挥它的作用。
如果Animator Controller控制多个Animation的播放,那么默认情况下Animator组件会播放哪个动画呢? 由Entry来决定的。
但是Entry本身并不包含动画,而是指向某个带有动画的状态,并设置其为默认状态。被设置为默认状态的状态会显示为 橘黄色。
在这里插入图片描述
当然,你可以随时在任意一个状态上通过 鼠标右键->Set as Layer Default State更改默认状态。
在这里插入图片描述

记住, EntryAnimator组件被激活后 无条件 跳转到默认状态,并且每个Layer有且仅有一个默认状态。

13.4.2.3 Exit状态

表示状态机的出口状态,以红色标识。如果你的动画控制器只有一层,那么这个状态可能并没有什么卵用。但是当你需要从子状态机中返回到上一层(Layer)时,把状态指向Exit就可以了。
在这里插入图片描述

13.4.3 动画状态的属性

我们可以选中某个自定义状态,并在Inspector窗口下观察它具有的属性
在这里插入图片描述

属性名描述
Motion状态对应的动画。每个状态的基本属性,直接选择已定义好的动画(Animation Clip)即可
Speed动画播放的速度。默认值为1,表示速度为原动画的1.0倍。
Mutiplier勾选右侧的Parameter后可用,即在计算Speed的时考虑 区域1 中定义的某个参数。若选择的参数为smooth, 则动画播放速度的计算公式为 smooth * speed * fps(animation clip中指定)
Mirror仅适用于humanoid animation(人型机动画)
Cycle Offset周期偏移,取值范围为0-1.0,用于控制动画起始的偏移量。把它和正弦函数的offset进行对比就能够理解了,只会影响起始动画的播放位置。
Foot IK仅适用于humanoid animation(人型机动画)
Write Default最好保持默认,感兴趣可以参考官方手册
Transitions该状态向其他状态发起的过渡列表,包含了Solo和Mute两个参数,在预览状态机的效果时起作用
Add Behaviour用于向状态添加“行为
13.4.4 状态间的过渡关系(Transitions)

状态间的过渡关系,直观上说它们就是连接不同状态的有向箭头。

在这里插入图片描述
要创建一个从状态A状态B的过渡,直接在状态A上 鼠标右键 - Make Transition并把出现的箭头拖拽到状态B上点击鼠标左边即可。
在这里插入图片描述

13.4.5 添加状态控制参数

参数有FloatIntBoolTrigger
在这里插入图片描述
FloatInt用来控制一个动画状态的参数,比如速度方向等可以用数值量化的东西,
Bool用来控制动画状态的转变,比如从走路转变到跑步,
Trigger本质上也是bool类型,但它默认为false,且当程序设置为true后,它会自动变回false

如下这里创建一个Int类型的参数AnimState
在这里插入图片描述

13.4.6 编辑切换状态的条件

点击连线,在Inspecter窗口中可以进行设置,在Conditions栏下可以添加条件,如下图表示当参数
AnimState0时会执行这个动画Any StateNew Animation2的过渡

必须在Parameters面板中添加了参数才可以在这里查看到,其次添加的条件为&& ”与” 关系,即必须同时满足。

在这里插入图片描述

13.5 猫娘动画状态机
13.5.1 模型资源下载

Assets Store上下载猫娘模型,资源地址:https://assetstore.unity.com/packages/2d/characters/fancydoll-c000-little-cat-girl-112776
在这里插入图片描述

13.5.2 动画循环设置

模型自带了一些动画
在这里插入图片描述
idle(站立)、walk(走路)、run(跑)需要循环播放,勾选Loop Time
在这里插入图片描述
get_hit(受击)、die(阵亡)不需要循环播放,不勾选Loop Time
在这里插入图片描述

13.5.3 状态过渡设置

我们需要通过Animator将这些动画进行合理的组织,如下
在这里插入图片描述
添加变量Action,过渡条件根据Action的值进行判断。
在这里插入图片描述
过渡条件如下

状态1状态2条件
Any StateidleAction == 1
Any Stateget_hitAction == 4
get_hitidle
Any StatedieAction == 5
13.6 角色动画控制器

角色动画控制器CharacterAniCtrler,它需要包括数据和逻辑,如下。
在这里插入图片描述
运行中的状态过渡
在这里插入图片描述

13.6.1 数据定义
	/// <summary>/// 状态定义,默认为Idle状态。/// </summary>public enum CharacterAniId{Idle = 1,Walk = 2,Run = 3,Hit = 4,Death = 5,}/// <summary>/// 角色动画Animator组件/// </summary>private Animator m_animator;/// <summary>/// 动画队列/// </summary>private Queue<int> m_animQueue = new Queue<int>();
13.6.2 直接播放动画接口
    /// <summary>/// 立即播放某个动画/// </summary>/// <param name="name">动画名称</param>private void PlayAniImmediately(string name){if (IsDeath) return;m_animator.CrossFade(name, 0.1f, 0);}

如立即播放走路动画

    public void PlayWalk(){PlayAniImmediately("walk");}
13.6.3 设置变量值
// 设置Action变量值为4m_animator.SetInteger("Action", 4);

封装成接口

	private const string STR_ACTION = "Action";/// <summary>/// 播放不同动作ID/// </summary>/// <param name="isJump"></param>/// public void PlayAnimation(int actionID){if (IsDeath) return;if (m_animator == null)return;if (!m_animator.isInitialized || m_animator.IsInTransition(0)){// 如果正在过渡,则先塞到队列中m_animQueue.Enqueue(actionID);return;}m_animator.SetInteger(STR_ACTION, actionID);}
13.6.4 根据状态队列设置状态

提供一个LateUpdate接口每帧调用,设置了Action值需要在下一帧的时候重置为0,然后从队列中取下一个状态进行处理。

    /// <summary>/// 每帧调用/// </summary>public void LateUpdate(){if (m_animator == null){return;}if (!m_animator.isInitialized || m_animator.IsInTransition(0)){return;}if (null == mClips)mClips = m_animator.GetCurrentAnimatorClipInfo(0);if (null == mClips || mClips.Length == 0)return;int actionID = m_animator.GetInteger(STR_ACTION);if (actionID > 0){//将Action复位m_animator.SetInteger(STR_ACTION, 0);}//将剩余队列的动作重新拿出来播放PlayRemainAction();}/// <summary>/// 将剩余队列的动作重新拿出来播放/// </summary>void PlayRemainAction(){if (m_animQueue.Count > 0){PlayAnimation(m_animQueue.Dequeue());}}
13.7 入口场景脚本

入口场景脚本EntryScene.cs挂在Canvas上,设置Start Game BtnTgl Group
在这里插入图片描述
代码如下

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;public class EntryScene : MonoBehaviour
{public Button startGameBtn;public ToggleGroup tglGroup;void Start(){startGameBtn.onClick.AddListener(() =>{// 根据勾选,缓存难度等级foreach (var item in tglGroup.ActiveToggles()){GameMgr.Instance.hardLevel = int.Parse(item.name);break;}// 进入Game场景SceneManager.LoadScene(1);});}
}
13.8 游戏场景脚本

游戏场景脚本GameScene.cs挂在Canvas上,设置公开的成员对象。
在这里插入图片描述
主要根据各种事件更新ui

using System;
using UnityEngine;
using UnityEngine.UI;public class GameScene : MonoBehaviour
{public Animator anitor;public Text comboText;public Text scoreText;public Slider bloodSlider;public Image bloodImage;public GameOverDlg gameOverDlg;public KeyGrid keyGrid;private CharacterAniCtrler m_aniCtrler;private void Awake(){// 注册事件EventDispatcher.Instance.Regist(EventNameDef.EVENT_KEY_BINGO_INDEX, OnEventKeyBingoIndex);EventDispatcher.Instance.Regist(EventNameDef.EVENT_COMBO, OnEventCombo);EventDispatcher.Instance.Regist(EventNameDef.EVENT_PLAY_ANI, OnEventPlayAni);EventDispatcher.Instance.Regist(EventNameDef.EVENT_UPDATE_SCORE, OnEventUpdateScore);EventDispatcher.Instance.Regist(EventNameDef.EVENT_RESTART_GAME, OnEventRestartGame);EventDispatcher.Instance.Regist(EventNameDef.EVENT_GAMEOVER, OnEventGameOver);m_aniCtrler = new CharacterAniCtrler();m_aniCtrler.Init(anitor);// 开始游戏StartGame();}private void OnDestroy(){// 注销事件EventDispatcher.Instance.UnRegist(EventNameDef.EVENT_KEY_BINGO_INDEX, OnEventKeyBingoIndex);EventDispatcher.Instance.UnRegist(EventNameDef.EVENT_COMBO, OnEventCombo);EventDispatcher.Instance.UnRegist(EventNameDef.EVENT_PLAY_ANI, OnEventPlayAni);EventDispatcher.Instance.UnRegist(EventNameDef.EVENT_UPDATE_SCORE, OnEventUpdateScore);EventDispatcher.Instance.UnRegist(EventNameDef.EVENT_RESTART_GAME, OnEventRestartGame);EventDispatcher.Instance.UnRegist(EventNameDef.EVENT_GAMEOVER, OnEventGameOver);}/// <summary>/// 开始游戏/// </summary>private void StartGame(){GameMgr.Instance.Init();TextEffect.Init();// 初始化血量bloodSlider.maxValue = GameMgr.Instance.blood;bloodSlider.value = GameMgr.Instance.blood;bloodImage.enabled = true;// 生成字母盘keyGrid.CreateKeyList(GameMgr.Instance.keyList);comboText.gameObject.SetActive(false);scoreText.text = "0";gameOverDlg.Hide();}void Update(){if (GameMgr.Instance.gameOver) return;// 更新连击定时器GameMgr.Instance.UpdateComboTimer();// 更新血量uibloodSlider.value = GameMgr.Instance.blood;GameMgr.Instance.blood -= GameMgr.Instance.hardLevel;// 按键判断var keyCode = GameMgr.Instance.GetKeyDownCode();if (KeyCode.None == keyCode) return;GameMgr.Instance.OnKey(keyCode);}private void LateUpdate(){// 更新动画控制器m_aniCtrler.LateUpdate();}/// <summary>/// 按键正确事件/// </summary>/// <param name="args"></param>private void OnEventKeyBingoIndex(params object[] args){int index = (int)args[0];KeyCode oldKey = (KeyCode)args[1];KeyCode newKey = (KeyCode)args[2];keyGrid.UpdateKeyByIndex(index, oldKey, newKey);}/// <summary>/// 连击事件/// </summary>/// <param name="args"></param>private void OnEventCombo(params object[] args){var combo = (int)args[0];comboText.text = "连击" + combo;comboText.gameObject.SetActive(combo >= 3);}/// <summary>/// 播放动画事件/// </summary>/// <param name="args"></param>private void OnEventPlayAni(params object[] args){var ani = (string)args[0];switch (ani){case "idle": m_aniCtrler.PlayAnimation((int)CharacterAniId.Idle); break;case "walk": GameMgr.Instance.comboTimer = 0.5f; m_aniCtrler.PlayWalk(); break;case "run": GameMgr.Instance.comboTimer = 0.5f; m_aniCtrler.PlayRun(); break;case "hit": m_aniCtrler.PlayAnimation((int)CharacterAniId.Hit); break;case "die": m_aniCtrler.PlayDieImmediately(); break;}}/// <summary>/// 更新得分事件/// </summary>/// <param name="args"></param>private void OnEventUpdateScore(params object[] args){var score = (int)args[0];scoreText.text = score.ToString();}/// <summary>/// 游戏结束事件/// </summary>/// <param name="args"></param>private void OnEventGameOver(params object[] args){bloodImage.enabled = false;gameOverDlg.Show(GameMgr.Instance.score);}/// <summary>/// 重新开始游戏事件/// </summary>/// <param name="args"></param>private void OnEventRestartGame(params object[] args){m_aniCtrler.PlayReviveImmediately();StartGame();}
}

其中事件定义如下

/// <summary>
/// 事件定义
/// </summary>
public class EventNameDef 
{/// <summary>/// 按键正确事件/// </summary>public const string EVENT_KEY_BINGO_INDEX = "EVENT_KEY_BINGO_INDEX";/// <summary>/// 连击事件/// </summary>public const string EVENT_COMBO = "EVENT_COMBO";/// <summary>/// 播放动画事件/// </summary>public const string EVENT_PLAY_ANI = "EVENT_PLAY_ANI";/// <summary>/// 游戏结束事件/// </summary>public const string EVENT_GAMEOVER = "EVENT_GAMEOVER";/// <summary>/// 更新得分事件/// </summary>public const string EVENT_UPDATE_SCORE = "EVENT_UPDATE_SCORE";/// <summary>/// 重新开始游戏事件/// </summary>public const string EVENT_RESTART_GAME = "EVENT_RESTART_GAME";
}
13.9 文字特效动画

在这里插入图片描述
制作一个TextEffect.prefab预设,添加动画如下。
在这里插入图片描述
由于游戏中需要重复显示这个特效,所以采用对象池方式。
特效动画结束时回收到对象池中,这样可以反复利用。为了监听动画结束,在动画的最后一帧添加帧事件。
在这里插入图片描述
创建一个TextEffect.cs脚本,挂到预设上,提供一个OnAnimationEnd共有方法

public void OnAnimationEnd()

这样就可以设置帧事件的响应函数了
在这里插入图片描述
TextEffect.cs脚本如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;/// <summary>
/// 文本特效
/// </summary>
public class TextEffect : MonoBehaviour
{/// <summary>/// 初始化/// </summary>public static void Init(){if(null != s_root){Destroy(s_root.gameObject);s_root = null;}s_objPool.Clear();var canvas = GameObject.Find("Canvas");if (null != canvas){var rootObj = new GameObject("EffectRoot");s_root = rootObj.transform;s_root.SetParent(canvas.transform, false);}}/// <summary>/// 显示特效/// </summary>/// <param name="text"></param>/// <param name="pos"></param>public static void Show(string text, Vector3 pos){if (null == s_prefab){s_prefab = Resources.Load<GameObject>("TextEffect");}TextEffect bhv = null;if (s_objPool.Count > 0){// 从对象池中取对象,bhv = s_objPool.Dequeue();}else{var obj = Instantiate(s_prefab);obj.transform.SetParent(s_root, false);bhv = obj.GetComponent<TextEffect>();}bhv.gameObject.SetActive(true);bhv.transform.position = pos;bhv.keyText.text = text;}/// <summary>/// 动画结束事件的响应函数/// </summary>public void OnAnimationEnd(){gameObject.SetActive(false);// 对象回收s_objPool.Enqueue(this);}private static GameObject s_prefab;/// <summary>/// 对象池/// </summary>private static Queue<TextEffect> s_objPool = new Queue<TextEffect>();/// <summary>/// 根节点/// </summary>private static Transform s_root;/// <summary>/// 文字组件/// </summary>public Text keyText;
}

完成。
如果有什么疑问,欢迎留言或私信。


《学Unity的猫》——第十四章:Unity实现文件上传下载,支持续传,猫后爪的秘密

这篇关于《学Unity的猫》——第十三章:Unity使用Animator控制动画播放,皮皮猫打字机游戏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/446616

相关文章

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]