Flappy Bird开发学习记录
概述
为了了解一下Unity的开发过程,或者说感受?先搞简单的练练手。
工具
Unity:2022.3.51f1c1
visual studio 2022
开发过程
项目基本设置
新建2d项目,游戏画面设置为1080*1920(9:16)。
图片素材设置为sprite
游戏画面搭建
Camera Size:相机画面高度的一半
Pixels Per Unit:每个单元格的像素长度
地面
新建地面GameObject,拖到相机底部,或者通过图片像素大小和相机高度来计算位置。
以Ground素材为例:其图片大小为37*128,Pixels Per Unit 为100。
相机高度(Camera Size)为8,在没有移动过相机的情况下,相机中心点为(0,0),相机底部位置为(0,-8),若要让Ground图片刚好在相机最底部,那么其Y轴为 − 8 + ( 128 100 ∗ 1 2 = − 7.36 ) -8+(\frac{128}{100} * \frac{1}{2} = -7.36) −8+(100128∗21=−7.36),Unity中可以直接输入算式然后Enter即可。
要将Ground平铺在底部,修改Draw Mode为Tiled,同时确保Ground素材的Sprite Mode为Single或者Multyple,以及MeshType为FullRect,避免报警告。
然后需要平铺几个Ground就把Ground的Width乘几,或者不在意也行,我没管。
背景
添加背景画面,将其DrawMode改为Sliced,同样MeshType设置为FullRect,然后点击Sprite Editor处理,切成九宫格(九宫格不同位置受拉伸影响不同),然后就可以拉伸了。
其实图片右侧还有一两个像素宽的灰色阴影,当采用两张背景平移轮播的方式时会有一条灰色的线在画面中移动,以AB的形式移动时候会有,A移出画面后挪到B后边时没有,很怪,于是我把图片右边黑色阴影涂成了旁边的颜色。
实现背景素材的连续滚动
public class BgMovement : MonoBehaviour
{private float BG_WIDTH = 9.8f;public Transform ground_1;public Transform ground_2;public Transform backGround_1;public Transform backGround_2;[Range(0,10)]public float moveSpeed = 3f;void Update(){if (GameStateManager.Instance.isFinish || GameStateManager.Instance.isPaused ) return;MoveBackground(ground_1, ground_2);MoveBackground(backGround_1, backGround_2);}private void MoveBackground(Transform obj1, Transform obj2){obj1.position -= new Vector3(moveSpeed * Time.deltaTime, 0, 0);obj2.position -= new Vector3(moveSpeed * Time.deltaTime, 0, 0);if (obj1.position.x < -BG_WIDTH){obj1.position = obj2.position + new Vector3(BG_WIDTH, 0, 0);}if (obj2.position.x < -BG_WIDTH){obj2.position = obj1.position + new Vector3(BG_WIDTH, 0, 0);}}
}
开始拼各种静态图片
其中的ReadyToStart是覆盖在画面上的一个按钮,目的是检测到点击之后正式开始游戏。
背景中的PieObj只是背景的一部分,所以checkpoint关闭,以防bug。
默认开启(活动?)的游戏对象,第一张图中亮着的以及GameOverUI下的全部,
默认关闭的游戏对象,GamingUI下的全部以及GameOverUI本身。
字体
别用TextMeshPro,不然这里边的字体可能没法用,反正我不会用,分数字体用Text组件就能用这里的字体了。
鸟的待机效果实现
待机动画制作
将鸟按三列一行的方式切分。
创建BirdAnimation,给动画添加关键帧,可以将图片直接拖到对应的时间点上。
注意,要先把Animation放在游戏对象上,然后确保选中的是目标游戏对象,才能把图片拖到它的Animation上作为关键帧。
待机动画控制
private void Idle(){Radian += R * Time.deltaTime;var height = Mathf.Sin(Radian) * IdleHeight;transform.position = orgPosition + new Vector3(0, height, 0);}
游戏的状态管理
因为在点击Start之后有一个引导等待画面,所以状态分为:
Start(主界面)->Ready(显示引导等待点击)->Playing(游戏中,真的开始游戏)->Finish(游戏结束),以及Paused(暂停状态)。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;// 主界面,点击start但是在游戏开始前的准备状态(此时显示游戏引导),游戏中状态,游戏结束状态,暂停
public enum GameState {Start, Ready, Playing, Finished, Paused }public class GameStateManager
{private static readonly Lazy<GameStateManager> instance = new Lazy<GameStateManager>(() => new GameStateManager());public static GameStateManager Instance => instance.Value;GameStateManager() { }public bool isStart;public bool isReady;public bool isPlaying;public bool isFinish;public bool isPaused;private MainPanel mainPanel;public void Setup(MainPanel panel){mainPanel = panel;}public void SetState(GameState state){switch (state){case GameState.Start:isStart = true; isReady = false; isPlaying = false; isFinish = false; isPaused = false; break;case GameState.Ready:isStart = false ; isReady = true; isPlaying = false; isFinish = false; isPaused = false; break;case GameState.Playing:isStart = false; isReady = false; isPlaying = true; isFinish = false; isPaused = false; break;case GameState.Finished:isStart = false; isReady = false; isPlaying = false; isFinish = true; isPaused = false;mainPanel.ShowGameOverUI();break;case GameState.Paused:isPaused = true;Time.timeScale = 0;break;}}// 游戏恢复public void Resume(){SetState(GameState.Playing); // 恢复游戏状态Time.timeScale = 1; // 恢复游戏速度}// 重启游戏public void Restart(){SetState(GameState.Start); // 设置为开始状态Time.timeScale = 1; // 恢复时间缩放}// 获取并更新分数public void GetScore(){int currentScore;if (int.TryParse(mainPanel.CurrentScore.text, out currentScore)){mainPanel.CurrentScore.text = (currentScore + 1).ToString();}}
}
游戏的控制
由于有一个暂停按钮在游戏中,当点击暂停按钮时同样会触发一次跳跃,所以对点击的位置进行判断。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;public class BirdController : MonoBehaviour
{[Range(1, 10)]public float R = 5f; // 控制小鸟上下浮动的速度[Range(0, 1)]public float IdleHeight = 0.5f; // 小鸟在待机状态时的浮动高度private float Radian = 0; // 当前浮动的角度(弧度)private Vector3 orgPosition; // 初始位置public float Gravity = -9.81f; // 重力加速度public float JumpHeight = 1.3f; // 跳跃高度public Vector3 Velocity = Vector3.zero; // 当前速度public float MaxVelocity = -15f; // 最大下落速度private float RotationZ = 0; // 小鸟的旋转角度public float RotateSpeed = 8; // 旋转速度(弧度)private float JumpVelocity; // 跳跃的初始速度private Collider2D preCollieder; // 上次碰撞的物体void Start(){orgPosition = transform.position; // 记录小鸟的初始位置preCollieder = null; // 初始化碰撞器}// Update is called once per framevoid Update(){if (GameStateManager.Instance.isPaused) return;if (GameStateManager.Instance.isStart || GameStateManager.Instance.isReady){Idle();}else if (GameStateManager.Instance.isPlaying){CustomGravity();}else if(GameStateManager.Instance.isFinish){HandleBirdDie();}}// 控制小鸟在待机状态时的上下浮动private void Idle(){Radian += R * Time.deltaTime; var height = Mathf.Sin(Radian) * IdleHeight; // 根据角度计算当前浮动高度transform.position = orgPosition + new Vector3(0, height, 0); }// 控制小鸟的重力和跳跃private void CustomGravity(){if ((Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began) || Input.GetMouseButtonDown(0) ){Vector2 clickPosition;// 获取点击位置if (Input.touchCount > 0){clickPosition = Input.GetTouch(0).position; // 触摸位置}else{clickPosition = Input.mousePosition; // 鼠标位置}if (!InitSceenSize.ClickPause(clickPosition)){// 如果点击位置不在暂停按钮区域内,触发跳跃Jump();}//if (GameStateManager.Instance.isPlaying) Jump();}Velocity.y += Gravity * Time.deltaTime; // 受重力影响更新垂直速度if (Velocity.y < MaxVelocity) Velocity.y = MaxVelocity; // 限制最大下落速度transform.position += Velocity * Time.deltaTime; // 更新小鸟的位置// 控制小鸟的旋转角度,使其根据下落速度旋转if (Velocity.y < -JumpVelocity * 0.1f){RotationZ -= RotateSpeed * Time.deltaTime * 1000 * Mathf.Deg2Rad; // 放大1000倍才显得正常,帧率太高导致deltaTime过低?RotationZ = Mathf.Max(-90, RotationZ);// 限制旋转角度不超过-90°}transform.eulerAngles = new Vector3(0, 0, RotationZ);}// 鸟作为触发器去接触其他物体,要么是其他物体都设置为触发器检测是否碰到鸟,那么需要给每个会碰到鸟的物体写脚本。// 如果碰到后那些物体需要各种处理的话,也许其他作为触发器好点,毕竟还要给它们写其他东西。// 如果东西多的话,鸟要接触的东西太多了,集中在这里看起来也许不如分散到各自身上处理private void OnTriggerEnter2D(Collider2D collision){//Debug.Log(collision.tag);if(collision.CompareTag("ground") || collision.CompareTag("pipe")){//GameStateManager.Instance.Finish();GameStateManager.Instance.SetState(GameState.Finished);}if (collision.CompareTag("sky")){Velocity = new Vector3(0, -2, 0);}// 避免刚好接触时死亡,触发两次加分的情况if (collision.CompareTag("checkPoint") && ((preCollieder==null)|| preCollieder.GetComponent<Transform>().position != collision.GetComponent<Transform>().position)){GameStateManager.Instance.GetScore();preCollieder = collision;}}// 防止卡进去然后穿过去private void OnTriggerStay2D(Collider2D collision){if (collision.CompareTag("sky")){Velocity = new Vector3(0, -2, 0);}}private void HandleBirdDie(){float distance = -Camera.main.orthographicSize + 1.28f + 0.64f * 0.5f; // 通过手动计算得到的地面高度if(transform.position.y > distance){CustomGravity();}}// 重启游戏时重置小鸟的位置和状态public void Restart(){transform.position = orgPosition; // 恢复初始位置transform.eulerAngles = Vector3.zero; // 恢复旋转角度RotationZ = 0; // 恢复旋转值Velocity = Vector3.zero; // 恢复速度}// 使小鸟跳跃public void Jump(){Velocity.y = MathF.Sqrt(JumpHeight * -2 * Gravity); // 计算跳跃的初始速度JumpVelocity = Velocity.y; // 记录跳跃速度RotationZ = 30; // 跳跃时调整旋转角度}
}
障碍物的创建与控制
障碍物的创建
用两个管道图片拼接而成,给图片添加碰撞体,添加空游戏对象最为检查点,添加碰撞体,设置合适的位置和大小,注意设置tag。创建为预制体
障碍物的控制
using System.Collections.Generic;
using UnityEngine;public class PipeCreate : MonoBehaviour
{public BgMovement bgMove;private List<GameObject> pipeList;private float Distance = 5f;private float CameraHalfWidth;private GameObject pipePrefab;// Start is called before the first frame updatevoid Start(){pipePrefab = Resources.Load<GameObject>("Prefab/PipeObj"); // 只加载一次CameraHalfWidth = Screen.width * 1f / Screen.height * Camera.main.orthographicSize;//Debug.Log(CameraHalfWidth);pipeList = new List<GameObject>();// 也能通过协程的方式不断生成for(int i =0; i< 5;i++){var go = GameObject.Instantiate(pipePrefab);go.transform.position = new Vector3(i * Distance, Random.Range(-3f,4.5f), 0) + new Vector3(8,0,0);go.transform.SetParent(this.transform,true);pipeList.Add(go);}}public void Restart(){for (int i = 0; i < 5; i++){var go = pipeList[i];go.transform.position = new Vector3(i * Distance, Random.Range(-3f, 4.5f), 0) + new Vector3(8, 0, 0);}}// Update is called once per framevoid Update(){if(GameStateManager.Instance.isPlaying){foreach (var item in pipeList){item.transform.position += new Vector3(-Time.deltaTime * bgMove.moveSpeed, 0, 0);if (item.transform.position.x < -CameraHalfWidth - 1){var lastPipe = pipeList[pipeList.Count - 1];item.transform.position = lastPipe.transform.position + new Vector3(Distance, 0, 0);item.transform.position = new Vector3(lastPipe.transform.position.x + Distance, Random.Range(-3f, 4.5f), 0);pipeList.Remove(item);pipeList.Add(item);return;}}}}}
画面的控制与管理:开始,准备,游戏中,结束,暂停
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
using Unity.VisualScripting;public class MainPanel : MonoBehaviour
{// 开始界面public Button StartButton;public Button RestartButton;public Image Title;public GameObject UIPipe;public CanvasGroup StartUI;// 准备界面public Button ReadyToStart; public CanvasGroup Tutorial;// 游戏界面public Text CurrentScore;public Button PauseButton;public Button ResumeButton;// 结束界面public GameObject GameOverUI;public Text FinalScore;public Text BestScore;public Image Medal;public List<Sprite> Medals;public Image NewIcon;public BirdController birdController;public PipeCreate pipeCreate;private float FadeTime = 0.4f;private bool isClickStart;// Start is called before the first frame updatevoid Start(){StartButton.onClick.AddListener(OnClickStart);RestartButton.onClick.AddListener(OnClickRestart);ReadyToStart.onClick.AddListener(GameStart);PauseButton.onClick.AddListener(OnClickPause);ResumeButton.onClick.AddListener(OnClickResume);GameOverUI.gameObject.SetActive(false);ReadyToStart.gameObject.SetActive(false);NewIcon.gameObject.SetActive(false);isClickStart = false;CurrentScore.text = "0";GameStateManager.Instance.Setup(this);GameStateManager.Instance.SetState(GameState.Start);}private void OnClickStart(){// 点击过快会触发两次点击,从而出现鸟跳跃被打断重新回到ready状态,在Restart恢复if (isClickStart) return;isClickStart = true;//GameStateManager.Instance.Ready();GameStateManager.Instance.SetState(GameState.Ready);// 恢复初始UI状态NewIcon.gameObject.SetActive(false);Medal.gameObject.SetActive(true);ShowReadyUI();}private void OnClickRestart(){GameStateManager.Instance.Restart();GameOverUI.gameObject.SetActive(false);ShowStartUI();}private void OnClickPause(){GameStateManager.Instance.SetState(GameState.Paused);ResumeButton.gameObject.SetActive(true);}private void OnClickResume(){GameStateManager.Instance.Resume();ResumeButton.gameObject.SetActive(false);}public void ShowStartUI(){// 已被隐藏且关闭,先启用,再渐显Title.gameObject.SetActive(true);StartButton.gameObject.SetActive(true);isClickStart = false;StartUI.DOFade(1, FadeTime);UIPipe.gameObject.SetActive(true);CurrentScore.gameObject.SetActive(false);PauseButton.gameObject.SetActive(false);ResumeButton.gameObject.SetActive(false);birdController.Restart();pipeCreate.Restart();}public void ShowReadyUI(){// 隐藏UI,然后关闭UIStartUI.DOFade(0, FadeTime).onComplete = () =>{StartButton.gameObject.SetActive(false);Title.gameObject.SetActive(false);};UIPipe.gameObject.SetActive(false);CurrentScore.gameObject.SetActive(true);CurrentScore.text = "0";Tutorial.gameObject.SetActive(true);Tutorial.DOFade(1, FadeTime);ReadyToStart.gameObject.SetActive(true);}private void GameStart(){GameStateManager.Instance.SetState(GameState.Playing);birdController.Jump();Tutorial.DOFade(0, FadeTime).onComplete = () =>{Tutorial.gameObject.SetActive(false);};ReadyToStart.gameObject.SetActive(false);PauseButton.gameObject.SetActive(true);ResumeButton.gameObject.SetActive(false);}public void ShowGameOverUI(){int score = int.Parse(CurrentScore.text);CurrentScore.gameObject.SetActive(false);GameOverUI.gameObject.SetActive(true);PauseButton.gameObject.SetActive(false);ResumeButton.gameObject.SetActive(false);// 最高分处理if (score > PlayerPrefs.GetInt("BestScore")){PlayerPrefs.SetInt("BestScore", score);NewIcon.gameObject.SetActive(true);}if(score <10){Medal.gameObject.SetActive(false);}else if(score <20 && score >=10){Medal.sprite = Medals[0];}else if(score < 50&& score >= 20){Medal.sprite = Medals[1];}else if(score < 100 && score >=50){Medal.sprite = Medals[2];}else{Medal.sprite = Medals[3];}FinalScore.text = score.ToString();BestScore.text = PlayerPrefs.GetInt("BestScore").ToString();}}
屏幕设置
在手机上测试时,图片和按钮位置发生了偏移和拉伸,发现是因为我是按照1080*1920做的UI,但是我的手机是2400*1080,甚至用screensize获取手机的宽还是2400而不是1080,不知道其他手机是不是这样。所以通过比大小,把手机屏幕上小的边作为宽,大的作为高。
//int screen_min = Mathf.Min(screenHeight, screenWidth);
//int screen_max = Mathf.Max(screenWidth, screenHeight);//GetComponent<CanvasScaler>().scaleFactor = screen_min / (float)1080;
然后屏幕的宽来缩放,但是实际效果不太好,于是调整了UI的这个我也不知道叫啥的东西,修改他们的参考点。在不考虑会有更宽的手机的情况下,只对高度进行调整。
然后由于Start的先后顺序不一。忘了使用Awake了,不过问题不大,毕竟Awake虽然在Start之前调用,但是不同脚本之间,Awake是否真的能在Start之前我就不确定了。
所以一开始在InitScreenSize.cs中修改屏幕大小,然后在BirdControoller计算暂停按钮的位置,但是由于脚本先后顺序原因,画面虽然调整了,但是Bird中获取到的暂停按钮的坐标是一开始调整之前的坐标,导致点击暂停按钮的计算出现错误,又不希望每次点击都反复计算暂停按钮所在的边框,所以将暂停按钮的坐标计算放在了InitScreenSize脚本中。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class InitSceenSize : MonoBehaviour
{public RectTransform StartUI;public RectTransform GamingUI;public RectTransform FinishUI;private int screenWidth;private int screenHeight;public RectTransform pauseButtonRectTransform;private static float left;private static float right;private static float top;private static float bottom;void Start(){screenHeight = UnityEngine.Screen.height;screenWidth = UnityEngine.Screen.width;//int screen_min = Mathf.Min(screenHeight, screenWidth);//int screen_max = Mathf.Max(screenWidth, screenHeight);//GetComponent<CanvasScaler>().scaleFactor = screen_min / (float)1080;StartUI.sizeDelta = new Vector2(screenWidth, screenHeight);GamingUI.sizeDelta = new Vector2 (screenWidth, screenHeight);FinishUI.sizeDelta = new Vector2 (screenWidth, screenHeight);// 获取暂停按钮的世界坐标Vector3 buttonWorldPosition = pauseButtonRectTransform.position;// 获取暂停按钮的尺寸(宽度和高度)Vector2 buttonSize = pauseButtonRectTransform.rect.size;// 计算暂停按钮的四个边界位置left = buttonWorldPosition.x - buttonSize.x / 2;right = buttonWorldPosition.x + buttonSize.x / 2;top = buttonWorldPosition.y + buttonSize.y / 2;bottom = buttonWorldPosition.y - buttonSize.y / 2;//Debug.Log(pauseButtonRectTransform.position.y + "+" + pauseButtonRectTransform.rect.size.y / 2 + "=" + top);}public static bool ClickPause(Vector3 position){if (position.x >= left && position.x <= right && position.y >= bottom && position.y <= top){return true;}return false;}
}
参考链接
【Unity游戏开发:Flappy Bird (01)】
这是全B站最还原的2025-02-12-FlappyBird飞翔的小鸟!2025-02-12-FlappyBird开发教学合集!
素材资源
https://github.com/GameDevStation/2025-02-12-FlappyBirdDemo/blob/main/2025-02-12-FlappyBirdTexture.rar
https://pan.baidu.com/s/1Mo8wZoTr9jjelMK-28b1Cw
素材我也放项目的Asset下备份了,以防两位的链接失效。
仓库链接
MapleInori/2025-02-12-FlappyBird (github.com)
闲话
梳理这种东西好累啊,感觉要考虑的东西好多,我还是太菜了呜呜,什么时候能成为大佬呢。
素材里还有菜单按钮和排行榜按钮和分享按钮,但是我没去补充这些东西,有点超过我这个菜鸟的能力。
应该没把什么搞错。
相关文章:
Flappy Bird开发学习记录
概述 为了了解一下Unity的开发过程,或者说感受?先搞简单的练练手。 工具 Unity:2022.3.51f1c1 visual studio 2022 开发过程 项目基本设置 新建2d项目,游戏画面设置为1080*1920(9:16)。 图片素材设…...
Visual Studio 使用 “Ctrl + /”键设置注释和取消注释
问题:在默认的Visual Studio中,选择单行代码后,按下Ctrl /键会将代码注释掉,但再次按下Ctrl /键时,会进行双重注释,这不是我们想要的。 实现效果:当按下Ctrl /键会将代码注释掉,…...
CTF-WEB: 利用Web消息造成DOM XSS
如果索引中有类似如下代码 <!-- Ads to be inserted here --> <div idads> </div> <script>window.addEventListener(message, function(e) {document.getElementById(ads).innerHTML e.data;}); </script>这行代码的作用是将接收到的消息内容…...
2025 西湖论剑wp
web Rank-l 打开题目环境: 发现一个输入框,看一下他是用上面语言写的 发现是python,很容易想到ssti 密码随便输,发现没有回显 但是输入其他字符会报错 确定为ssti注入 开始构造payload, {{(lipsum|attr(‘global…...
常见的排序算法:插入排序、选择排序、冒泡排序、快速排序
1、插入排序 步骤: 1.从第一个元素开始,该元素可以认为已经被排序 2.取下一个元素tem,从已排序的元素序列从后往前扫描 3.如果该元素大于tem,则将该元素移到下一位 4.重复步骤3,直到找到已排序元素中小于等于tem的元素…...
LVDS接口总结--(5)IDELAY3仿真
仿真参考资料如下: https://zhuanlan.zhihu.com/p/386057087 timescale 1 ns/1 ps module tb_idelay3_ctrl();parameter REF_CLK 2.5 ; // 400MHzparameter DIN_CLK 3.3 ; // 300MHzreg ref_clk ;reg …...
数据库的基本概念
在当今的信息时代,数据已成为企业乃至整个社会的重要资产。如何有效地存储、管理和利用这些数据成为了技术发展的关键领域之一。数据库系统作为数据管理的核心工具,在软件开发、数据分析等多个方面扮演着不可或缺的角色。本文将带你了解数据库的一些基本…...
Redis性能优化
1.是否使用复杂度过高的命令 首先,第一步,你需要去查看一下 Redis 的慢日志(slowlog)。 Redis 提供了慢日志命令的统计功能,它记录了有哪些命令在执行时耗时比较久。 查看 Redis 慢日志之前,你需要设置慢…...
CCF-CSP第34次认证第二题——矩阵重塑(其二)【需反复思考学习!!!】
第34次认证第二题——矩阵重塑(其二) 官网题目链接 时间限制: 1.0 秒 空间限制: 512 MiB 相关文件: 题目目录(样例文件) 题目背景 矩阵转置操作是将矩阵的行和列交换的过程。在转置过程中&…...
大模型DeepSeek-R1学习
学习路线 机器学习-> 深度学习-> 强化学习-> 深度强化学习 大模型演进分支 微调: SFT 监督学习蒸馏:把大模型作为导师训练小模型RLHF:基于人类反馈的强化学习 PPO 近端策略优化 油门 - 重要性采样 权重 * 打分刹车 - clip 修剪…...
Spring Cloud — 深入了解Eureka、Ribbon及Feign
Eureka 负责服务注册与发现;Ribbon负责负载均衡;Feign简化了Web服务客户端调用方式。这三个组件可以协同工作,共同构建稳定、高效的微服务架构。 1 Eureka 分布式系统的CAP定理: 一致性(Consistency)&am…...
19.4.9 数据库方式操作Excel
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 本节所说的操作Excel操作是讲如何把Excel作为数据库来操作。 通过COM来操作Excel操作,请参看第21.2节 在第19.3.4节【…...
《深度LSTM vs 普通LSTM:训练与效果的深度剖析》
在深度学习领域,长短期记忆网络(LSTM)以其出色的处理序列数据能力而备受瞩目。而深度LSTM作为LSTM的扩展形式,与普通LSTM在训练和效果上存在着一些显著的不同。 训练方面 参数数量与计算量:普通LSTM通常只有一层或较少…...
认识一下redis的分布式锁
Redis的分布式锁是一种通过Redis实现的分布式锁机制,用于在分布式系统中确保同一时刻只有一个客户端可以访问某个资源。它通常用于防止多个应用实例在同一时间执行某些特定操作,避免数据的不一致性或竞争条件。 实现分布式锁的基本思路: 1. …...
untiy3D为游戏物体制作简单的动画
1.创建一个物体挂载动画组件Animator 2.创建一个动画控制器 3.动画控制器挂载到Animator组件 4.创建动画窗口>动画 入口默认执行left 执行效果 20250212_151707 脚本控制动画 鼠标点击是切换到动画t using System.Collections; using System.Collections.Generic; usi…...
微服务与网关
什么是网关 背景 单体项目中,前端只用访问指定的一个端口8080,就可以得到任何想要的数据 微服务项目中,ip是不断变化的,端口是多个的 解决方案:网关 网关:就是网络的关口,负责请求的路由、转发、身份校验。 前段还是访问之前的端口8080即可 后端对于前端来说是透明的 网…...
ArcGIS基础知识之ArcMap基础设置——ArcMap选项:常规选项卡设置及作用
作为一名 GIS 从业者,ArcMap 是我们日常工作中不可或缺的工具。对于初学者来说,掌握 ArcMap 的基础设置是迈向 GIS 分析与制图的第一步。今天,就让我们一起深入了解 ArcMap 选项中常规选项卡的各个设置,帮助大家更好地使用这款强大的软件。 在 ArcMap 中,常规选项卡是用户…...
Ubuntu轻松部署ToolJet低代码开发平台结合内网穿透远程访问
文章目录 前言1.关于ToolJet2.Docker部署3.简单使用演示4.安装cpolar内网穿透5. 配置公网地址6. 配置固定公网地址 前言 本文主要介绍如何在本地Linux服务器使用Docker部署轻量级开源文件分享系统ToolJet,并结合cpolar内网穿透工具轻松实现跨网络环境远程访问与使用…...
[MySQL]5-MySQL扩展(分片)
随着数据量和用户量增加,MySQL会有读写负载限制。以下是部分解决方案 目录 功能拆分 使用读池拓展读(较复杂) 排队机制 🌟分片拓展写 按业务或职责划分节点或集群 大数据集切分 分片键的选择 多个分片键 跨分片查询 资料…...
如何使用 DeepSeek 帮助自己的工作
Hi,我是布兰妮甜 !在当今快速发展的技术领域,人工智能(AI)工具已经成为提高工作效率、促进创新的重要助手。DeepSeek作为一款先进的AI解决方案,为用户提供了强大的数据处理、分析以及预测能力,可…...
Redis缓存穿透、击穿和雪崩面试相关问题整理
在互联网公司的面试中,Redis 的缓存穿透、击穿和雪崩是高频考点,尤其在北京的头部互联网公司(如字节、阿里、美团、快手等)。以下是针对这三个问题的详细解析及常见面试题方向: 一、缓存穿透(Cache Penetra…...
Flink之Watermark
Apache Flink 是一个分布式流处理框架,它非常擅长处理实时数据流。流处理中的一个关键挑战是事件时间的处理,因为在流式数据中,事件到达系统的顺序可能并不代表它们的实际发生时间。为了解决这一问题,Flink 引入了**Watermark&…...
vs构建网络安全系统 网络安全和网络搭建
网站的组成和搭建 网站由服务器,容器,脚本,数据库组成。 服务器和家庭电脑一样。 容器又为环境或服务:apache,lls,tomcat,nginx等 脚本:php,aspx,asp&#x…...
缓存穿透问题及解决方案
一、什么是缓存穿透? 在分布式系统中,缓存常常用于提高系统的性能,减轻数据库的压力。缓存穿透问题指的是请求的数据在缓存和数据库中都不存在,导致请求每次都直接查询数据库,无法从缓存中获取数据,从而绕…...
ElementUI el-popover弹框背景色设置
1.el-popover样式由于使用了 absolute 属性,导致脱离了节点,所以在父级元素使用class无法进行权重处理来修改其样式,解决方式如下:通过popper-class实现样式处理,避免全局样式污染 // html <el-popoverplacement&q…...
在 Mac ARM 架构上使用 nvm 安装 Node.js 版本 16.20.2
文章目录 1. 安装 nvm(如果还没有安装的话)2. 加载 nvm 配置3. 列出特定系列的 Node.js 版本(远程):4. 安装 Node.js 16.20.25. 使用指定版本的 Node.js6. 验证安装 在 Mac ARM 架构上使用 nvm 安装 Node.js 版本 16.…...
spring集成activiti流程引擎(源码)
前言 activiti工作流引擎项目,企业erp、oa、hr、crm等企事业办公系统轻松落地,请假审批demo从流程绘制到审批结束实例。 源码获取:本文末个人名片直接获取。 一、项目形式 springbootvueactiviti集成了activiti在线编辑器,流行…...
VLLM历次会议(2024.4)
Prefix Caching。预先算好KV cache,遇见公共前缀,复用之,避免再计算一遍。 场景:1. 多轮对话。2.公共的system prompt。 Guided Decoding(格式化输出) 通过Outlines工具实现。 支持正则表达式、JSON格式等。 输入:…...
基于 Docker 搭建 Elasticsearch + Kibana 环境
一、Elasticsearch 1. 下载镜像 elasticsearch镜像不支持latest标签,必须指定版本号 % docker pull elasticsearch:8.17.2 2. 启动容器 参考官方文档 https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docker.html % docker run -p 9200:9200 -p 9…...
在 ARM64 架构系统离线安装 Oracle Java 8 全流程指南
在 ARM64 架构系统离线安装 Oracle Java 8 全流程指南 文章目录 在 ARM64 架构系统离线安装 Oracle Java 8 全流程指南一、引言二、下载前的准备2.1 确认系统架构2.2 注册 Oracle 账号 三、从 Oracle 官方下载 Java 8 for ARM643.1 访问 Oracle Java 存档页面3.2 选择合适的版本…...
策略模式-小结
总结一下看到的策略模式: A:一个含有一个方法的接口 B:具体的实行方式行为1,2,3,实现上面的接口。 C:一个环境类(或者上下文类),形式可以是:工厂模式,构造器注入模式,枚举模式。 …...
记一次Self XSS+CSRF组合利用
视频教程在我主页简介或专栏里 (不懂都可以来问我 专栏找我哦) 目录: 确认 XSS 漏洞 确认 CSRF 漏洞 这个漏洞是我在应用程序的订阅表单中发现的一个 XSS 漏洞,只能通过 POST 请求进行利用。通常情况下,基于 POST 的…...
VSCode + Continue 实现AI编程助理
安装VS Code 直接官网下载安装,反正是免费的。 安装VS插件Continue 直接在插件市场中搜索, Continue,第一个就是了。 配置Chat Model 点击Add Chat model后进行选择: 选择Ollama后,需要点击下面的config file : 由于…...
使用Typescript开发Babylon.js的Vue3模板参考
main.js文件 // main.ts import { createApp } from vue import App from ./App.vuecreateApp(App).mount(#app) App.vue文件 <!-- App.vue --> <template><div class"app-container"><BabylonScene /></div> </template><…...
STM32+Proteus+DS18B20数码管仿真实验
1. 实验准备 硬件方面: 了解 STM32 单片机的基本原理和使用方法,本实验可选用常见的 STM32F103 系列。熟悉 DS18B20 温度传感器的工作原理和通信协议(单总线协议)。数码管可选用共阴极或共阳极数码管,用于显示温度值。…...
DeepSeek自然语言处理(NLP)基础与实践
自然语言处理(Natural Language Processing, NLP)是人工智能领域的一个重要分支,专注于让计算机理解、生成和处理人类语言。NLP技术广泛应用于机器翻译、情感分析、文本分类、问答系统等场景。DeepSeek提供了强大的工具和API,帮助我们高效地构建和训练NLP模型。本文将详细介…...
Baklib优化数字化内容管理用科技提升商业效率与增值潜力
内容概要 在当今数字化迅速发展的时代,数字化内容管理已成为企业提升竞争力的重要手段。Baklib作为一款强大的智能优化内容管理系统,通过先进的科技手段,帮助企业在内容管理和数据整合方面实现高效运作。Baklib 是什么类型的工具,…...
视频基础操作
1.1. 例子 读取mp4格式的视频,将每一帧改为灰度图,并且打上水印(“WaterMark”),并将其输出保存为out.mp4,在这个例子中可以看到视频读取,每帧数据处理,视频保存的整体流程简单示例 import cv…...
写一个鼠标拖尾特效
思路和逻辑 要实现鼠标拖尾特效,我们需要: 监听鼠标移动事件,获取鼠标的当前位置。在每次鼠标移动时,绘制一个小圆点或其他形状在鼠标的当前位置。将所有绘制的圆点连接起来,形成一条“尾巴”。使用动画效果让尾巴看…...
Docker上安装Zabbix-server-mysql报错
创建新的zabbix server (mysql)容易,最后一条日志报错 cannot usedatabase"zabbix": its "users" table is empty (is this the Zabbix proxy database?) 往前还有一条关键报错信息 ERROR 1153 (08S01): Got a packe…...
<tauri><rust><GUI>使用tauri创建一个图片浏览器(文件夹遍历、图片切换)
前言 本文是基于rust和tauri,由于tauri是前、后端结合的GUI框架,既可以直接生成包含前端代码的文件,也可以在已有的前端项目上集成tauri框架,将前端页面化为桌面GUI。 环境配置 系统:windows 10平台:visual studio code语言:rust、javascript库:tauri2.0概述 本文是…...
【STM32系列】利用MATLAB配合ARM-DSP库设计IIR数字滤波器(保姆级教程)
ps.源码放在最后面 设计FIR数字滤波器可以看这里:利用MATLAB配合ARM-DSP库设计FIR数字滤波器(保姆级教程) 设计IIR滤波器 MATLAB配置 设计步骤 首先在命令行窗口输入"filterDesigner",接着就会跳出以下界面…...
迷宫(信息学奥赛一本通-1215)
【题目描述】 一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由nn的格点组成,每个格点只有2种状态,.和#,前者表示可以通行后者表示不能通行。同时当Extense处在某个格点时,他只能移动到东南西北(或…...
centos7 curl#6 - Could not resolve host mirrorlist.centos.org; 未知的错误 解决方案
问题描述 centos7系统安装完成后,yum安装软件时报错“curl#6 - “Could not resolve host: mirrorlist.centos.org; 未知的错误”” [root192 ~]# yum install vim -y 已加载插件:fastestmirror Determining fastest mirrors Could not retrieve mirro…...
Ubuntu安装PgSQL17
参考官网教程,Ubuntu24 apt在线安装Postgres 17 1. 要手动配置 Apt 存储库 # 导入存储库签名密钥: sudo apt install curl ca-certificates sudo install -d /usr/share/postgresql-common/pgdg sudo curl -o /usr/share/postgresql-common/pgdg/apt…...
在 Navicat 17 中扩展 PostgreSQL 数据类型 - 范围类型
范围类型 PostgreSQL 是市场上最灵活的数据库之一,这已不是什么秘密。事实上,PostgreSQL 的可扩展性和丰富的功能集使 PostgreSQL 近期已超越 MySQL,成为最受开发人员推崇和最受欢迎的数据库系统。在这个使用 Navicat Premium 17 在 Postgre…...
VMware Workstate 的 Ubuntu18 安装 vmware tools(不安装没法共享)
在共享主机路径后,可以在: /mnt/hgfs/下方找到共享的文件。但没有安装vmware tool时是没法共享的。 如何安装vmware tool,网上版本很多。这里记录一下: VMware Workstation 17 Pro,版本:17.6.0 虚拟机系统…...
稀土抑烟剂——为汽车火灾安全增添防线
一、稀土抑烟剂的基本概念 稀土抑烟剂是一类基于稀土元素(如稀土氧化物和稀土金属化合物)开发的高效阻燃材料。它可以显著提高汽车内饰材料的阻燃性能,减少火灾发生时有毒气体和烟雾的产生。稀土抑烟剂不仅能提升火灾时的安全性,…...
【工业安全】-CVE-2019-17621-D-Link Dir-859L 路由器远程代码执行漏洞
文章目录 1.漏洞描述 2.环境搭建 3.漏洞复现 4.漏洞分析 4.1:代码分析 4.2:流量分析 5.poc代码: 1.漏洞描述 漏洞编号:CVE-2019-17621 漏洞名称:D-Link DIR-859 命令注入漏洞 威胁等级:严重 漏洞详…...
git 记录
git 记录 报错warning: unknown value given to http.version: 2 报错 warning: unknown value given to http.version: ‘2’ 删除指定http版本 git config --global --unset http.version...