Unity之PUN实现多人联机射击游戏的优化

news2024/11/17 0:34:10

目录

🎮一、 跳跃,加速跑

🎮二、玩家自定义输入昵称

🍅2.1 给昵称赋值

🍅2.2 实现 

🎮三、玩家昵称同步到房间列表

🍅3.1 获取全部玩家 

🍅3.2 自定义Player中的字段

🍅3.3 实现

🎮四、计分板功能的实现

🍅4.1 设置玩家分数

🍅4.2 实现


前几天对之前肝出的射击游戏Demo进行了小小的优化,顺便在了解一下PUN插件。怎么实现的这个Demo可以来看一下这篇文章:

Unity之PUN2插件实现多人联机射击游戏-CSDN博客文章浏览阅读1.1k次,点赞19次,收藏19次。周五的下午永远要比周六幸福,周五好啊大家有在认真摸鱼吗。前两天我突发奇想想做联机游戏,就去找教程,肝了一天终于做出来了。先说一下搜寻资料过程中找到的实现游戏联机暂时就记录了这11个,做的这个实例是通过PUN2实现的,先看一下效果:个人感觉这套模型和这个教程泰裤辣,能跟着做完这个游戏Demo也是很开心的,下面依然以博客的形式记录实现这个游戏的过程。https://blog.csdn.net/qq_48512649/article/details/136249522来看一下优化完的效果。

关于优化了哪几个小点:

  • 点击开始游戏玩家可以输入自己的昵称;进入到房间后玩家对应的昵称也会同步显示到房间列表上;
  • 和朋友一起玩的时候他说会卡进房间的模型里建议我加上跳跃功能,我就给加上了,顺便加了一个按住Shift和方向键进行加速跑;
  • 同时按住Tab键会显示出计分板。虽然弹道很飘,但是命中伤害是按照准星射线来处理的,这个计分板也是按照射击命中次数来计分的。

下面来记录一下这几点优化是怎么实现的

一、 跳跃,加速跑

相信对于Unity入门的人来说这两点太简单了,废话不多说直接上代码。在PlayerController这个脚本中

    public float MoveSpeed = 3f;  //只按方向键速度为3
    /// <summary>
    /// 跳跃
    /// </summary>
    public float jumpHeight = 0;

    //判断是否为跳跃状态
    private bool boolJump = false;

    void Update()
    {
        //Debug.Log(photonView.Owner.NickName);
        //判断是否是本机玩家  只能操作本机角色
        if (photonView.IsMine)
        {
            if (isDie == true)
            {
                return;
            }
            //在Update函数中如果判断为本机操控的玩家就执行更新位置的方法
            UpdatePosition();
            UpdateRotation();
            InputCtl();
        }
        else
        {
            UpdateLogic();
        }
    }

    void FixedUpdate()
    {
        body.velocity = new Vector3(dir.x, body.velocity.y, dir.z) + Vector3.up * jumpHeight;
        jumpHeight = 0f;//初始化跳跃高度
    }

    //更新位置
    public void UpdatePosition()
    {
        H = Input.GetAxisRaw("Horizontal");
        V = Input.GetAxisRaw("Vertical");
        dir = camTf.forward * V + camTf.right * H;
        body.MovePosition(transform.position + dir * Time.deltaTime * MoveSpeed);
        //当按下空格键进行跳跃
        if (Input.GetKeyDown(KeyCode.Space))
        {
            if (boolJump == false)
            {
                boolJump = true;
                //设定一个跳跃时间间隔,不然就能一直往上跳了
                Invoke("something", 1.0f);
                //执行跳跃方法
                Jump();
            }
        }
        //加速跑  当同时按住Shift 和 方向键
        if (Input.GetKey(KeyCode.LeftShift) && (dir.x != 0 || dir.y != 0 || dir.z != 0))
        {
            body.MovePosition(transform.position + dir * Time.deltaTime * 10);
        }
        //当抬起 Shift 键
        else if (Input.GetKeyUp(KeyCode.LeftShift))
        {
            body.MovePosition(transform.position + dir * Time.deltaTime * MoveSpeed);
        }
    }

    void something() {
        boolJump = false;
    }
    
    //跳跃方法
    void Jump()
    {
        jumpHeight = 5f;
    }

二、玩家自定义输入昵称

2.1 给昵称赋值

首先说一下在PUN插件中给玩家昵称赋值的代码,赋好值之后我们只要进行获取就可以了

//playerNameInput.text —— 玩家手动输入的名字
PhotonNetwork.NickName = playerNameInput.text; 

2.2 实现 

UI方面小编就比较省事了,输入昵称和输入房间号用的同一个UI界面。在登录UI的LoginUI脚本中,点击开始游戏按钮我们不让它直接进行连接,先让它跳转到输入昵称的UI界面中。

//登录界面
public class LoginUI : MonoBehaviour //,IConnectionCallbacks
{
    // Start is called before the first frame update
    void Start()
    {
        transform.Find("startBtn").GetComponent<Button>().onClick.AddListener(onStartBtn);
        transform.Find("quitBtn").GetComponent<Button>().onClick.AddListener(onQuitBtn);
    }

    public void onStartBtn()
    {
        //弹出输入玩家昵称的UI界面 CreatePlayerUI
        Game.uiManager.ShowUI<CreatePlayerUI>("CreatePlayerUI");
    }

    public void onQuitBtn()
    {
        Application.Quit();
    }


}

 CreatePlayerUI脚本中进行连接并通过PhotonNetwork.NickName给玩家昵称赋值

using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine.UI;

public class CreatePlayerUI : MonoBehaviour,IConnectionCallbacks
{
    private InputField playerNameInput;  //玩家名称

    void Start()
    {
        transform.Find("bg/title/closeBtn").GetComponent<Button>().onClick.AddListener(onCloseBtn);
        transform.Find("bg/okBtn").GetComponent<Button>().onClick.AddListener(onStartBtn);
        playerNameInput = transform.Find("bg/InputField").GetComponent<InputField>();

        //先随机一个玩家名称
        playerNameInput.text = "Player_" + Random.Range(1, 9999); 
    }
    
    public void onStartBtn()
    {
        Game.uiManager.ShowUI<MaskUI>("MaskUI").ShowMsg("正在连接服务器...");
        
        //连接pun2服务器
        PhotonNetwork.ConnectUsingSettings();   //成功后会执行OnConnectedToMaster函数
    }
    
    //关闭按钮
    public void onCloseBtn()
    {
        Game.uiManager.CloseUI(gameObject.name);
    }
    
    //OnEnable()每次激活组件都会调用一次
    private void OnEnable()
    {
        PhotonNetwork.AddCallbackTarget(this);  //注册pun2事件
    }
    
    //OnDisable()每次关闭组件都会调用一次 与 OnEnable() 相对
    private void OnDisable()
    {
        PhotonNetwork.RemoveCallbackTarget(this);  //注销pun2事件
    }

    //连接成功后执行的函数
    public void OnConnectedToMaster()
    {
        //关闭所有界面
        Game.uiManager.CloseAllUI();
        Debug.Log("连接成功");
        //显示大厅界面
        Game.uiManager.ShowUI<LobbyUI>("LobbyUI");
        
        //执行昵称赋值操作
        PhotonNetwork.NickName = playerNameInput.text;
    }

    //断开服务器执行的函数
    public void OnDisconnected(DisconnectCause cause)
    {
        Game.uiManager.CloseUI("MaskUI");
    }

    public void OnRegionListReceived(RegionHandler regionHandler)
    {
        
    }

    public void OnCustomAuthenticationResponse(Dictionary<string, object> data)
    {
        
    }

    public void OnCustomAuthenticationFailed(string debugMessage)
    {
        
    }
    
    public void OnConnected()
    {
        
    }
}

三、玩家昵称同步到房间列表



3.1 获取全部玩家 

 PUN插件中从服务器获取房间里的全部玩家:

//从服务器遍历房间里的所有玩家项
for (int i = 0; i < PhotonNetwork.PlayerList.Length; i++)
{
    Player p = PhotonNetwork.PlayerList[i];
    //打印出玩家昵称,看看我们赋没赋值成功
    Debug.Log("NickName:" + p.NickName);
}

PUN插件的Player类中,NickName(玩家昵称)和ActorNumber(玩家编号)字段是Player类源码中定义的字段,如果我们开发者需要自定义字段可以通过这样来自定义:Demo中玩家是否准备就是用下面的方式来定义的

3.2 自定义Player中的字段

同步自定义字段:

using ExitGames.Client.Photon;
Hashtable props = new Hashtable() { { "IsReady", true } };
PhotonNetwork.LocalPlayer.SetCustomProperties(props);

 获取自定义字段:

foreach (Player p in PhotonNetwork.PlayerList)
{
    print(p.NickName);
 
    object isPlayerReady;
    if (p.CustomProperties.TryGetValue("IsReady", out IsReady))
    {
        print((bool)IsReady ? "当前玩家已准备好" : "当前玩家未准备好");
    }
}

//获取所有自定义字段
Debug.Log(玩家Player.CustomProperties.ToStringFull());

 3.3 实现

  1. 获取房间内所有的玩家信息包括昵称和准备状态
  2. 将昵称和准备状态显示到UI界面中

RoomUI脚本中,先获取房间内的所有玩家,对应的每一个玩家就会生成一个新的RoomItem

我们给房间列表成员RoomItem中添一个玩家昵称的字段,用来获取玩家进入游戏输入的昵称并展示在UI界面中。 

public int owerId;  //玩家编号
public bool IsReady = false; //是否准备
public string playerName; //玩家名称

 RoomUI脚本:

using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine.UI;

public class RoomUI : MonoBehaviour,IInRoomCallbacks
{
    Transform startTf; 
    Transform contentTf;
    GameObject roomPrefab;
    public List<RoomItem> roomList;
    
    private void Awake()
    {
        roomList = new List<RoomItem>();
        contentTf = transform.Find("bg/Content");
        //房间列表玩家成员
        roomPrefab = transform.Find("bg/roomItem").gameObject;
        transform.Find("bg/title/closeBtn").GetComponent<Button>().onClick.AddListener(onCloseBtn);
        startTf = transform.Find("bg/startBtn");
        startTf.GetComponent<Button>().onClick.AddListener(onStartBtn);
        PhotonNetwork.AutomaticallySyncScene = true; //执行PhotonNetwork.LoadLevel加载场景的时候 其他玩家也跳转相同的场景
    }

    void Start()
    {
        //从服务器获取房间里的玩家项
        for (int i = 0; i < PhotonNetwork.PlayerList.Length; i++)
        {
            Player p = PhotonNetwork.PlayerList[i];
            Debug.Log("NickName:" + p.NickName);
            //获取房间中的玩家后,每一个玩家生成对应的一个Item
            CreateRoomItem(p);
        }
    }

    private void OnEnable()
    {
        PhotonNetwork.AddCallbackTarget(this);
    }

    private void OnDisable()
    {
        PhotonNetwork.RemoveCallbackTarget(this);
    }

    //生成玩家
    public void CreateRoomItem(Player p)
    {
        GameObject obj = Instantiate(roomPrefab, contentTf);
        obj.SetActive(true);
        RoomItem item = obj.AddComponent<RoomItem>();
        item.owerId = p.ActorNumber;  //玩家编号
        item.playerName = p.NickName; //玩家昵称
        item.playerNameText(item.playerName);   //让玩家昵称显示到UI界面中
        
        roomList.Add(item);
        object val;
        if (p.CustomProperties.TryGetValue("IsReady", out val))
        {
            item.IsReady = (bool)val;
        }
    }

    //删除离开房间的玩家
    public void DeleteRoomItem(Player p)
    {
        RoomItem item = roomList.Find((RoomItem _item) => { return p.ActorNumber == _item.owerId; });
        if (item != null)
        {
            Destroy(item.gameObject);
            roomList.Remove(item);
        }
    }

    //关闭
    void onCloseBtn()
    {
        //断开连接
        PhotonNetwork.Disconnect();
        Game.uiManager.CloseUI(gameObject.name);
        Game.uiManager.ShowUI<LoginUI>("LoginUI");
    }
    
    //开始游戏
    void onStartBtn()
    {
         //加载场景 让房间里的玩家也加载场景
         PhotonNetwork.LoadLevel("game");
    }

    //新玩家进入房间
    public void OnPlayerEnteredRoom(Player newPlayer)
    {
        CreateRoomItem(newPlayer);
    }

    //房间里的其他玩家离开房间
    public void OnPlayerLeftRoom(Player otherPlayer)
    {
        DeleteRoomItem(otherPlayer);
    }

    public void OnRoomPropertiesUpdate(ExitGames.Client.Photon.Hashtable propertiesThatChanged)
    {
        
    }

    //玩家自定义参数更新回调
    public void OnPlayerPropertiesUpdate(Player targetPlayer, ExitGames.Client.Photon.Hashtable changedProps)
    {
        RoomItem item = roomList.Find((_item) => { return _item.owerId == targetPlayer.ActorNumber;});
        if (item != null)
        {
            item.IsReady = (bool)changedProps["IsReady"];
            item.ChangeReady(item.IsReady);
        }
        
        //如果是主机玩家判断所有玩家的准备状态
        if (PhotonNetwork.IsMasterClient)
        {
            bool isAllReady = true;
            for (int i = 0; i < roomList.Count; i++)
            {
                if (roomList[i].IsReady == false)
                {
                    isAllReady = false;
                    break;
                }
            }
            startTf.gameObject.SetActive(isAllReady); //开始按钮是否显示
        }
    }

    public void OnMasterClientSwitched(Player newMasterClient)
    {
        
    }
}

RoomItem脚本:

using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine.UI;


public class RoomItem : MonoBehaviour
{
    public int owerId;  //玩家编号
    public bool IsReady = false; //是否准备
    public string playerName; //玩家名称
    
    void Start()
    {
        if (owerId == PhotonNetwork.LocalPlayer.ActorNumber)
        {
            transform.Find("Button").GetComponent<Button>().onClick.AddListener(OnReadyBtn);
        }
        else
        {
            transform.Find("Button").GetComponent<Image>().color = Color.black;
        }

        ChangeReady(IsReady);
    }
    
    public void OnReadyBtn()
    {
        IsReady = !IsReady;

        ExitGames.Client.Photon.Hashtable table = new ExitGames.Client.Photon.Hashtable();
        
        table.Add("IsReady", IsReady);

        PhotonNetwork.LocalPlayer.SetCustomProperties(table); //设置自定义参数

        ChangeReady(IsReady);
    }

    public void ChangeReady(bool isReady)
    {
        transform.Find("Button/Text").GetComponent<Text>().text = isReady == true ? "已准备" : "未准备";
    }

    public void playerNameText(string playerName)
    {
        transform.Find("Name").GetComponent<Text>().text = playerName;
    }
}

四、计分板功能的实现

4.1 设置玩家分数

//设置玩家分数 
PhotonNetwork.LocalPlayer.SetScore(0);

PUN中有自带的设置玩家分数功能,我们来看一下源码:SetScoreAddScoreGetScore

通过方法的命名我们就知道它们分别是设置分数、增加分数、获取分数, 不过小编这里只用了设置和获取(*/ω\*),分数更新后把原有的重新设置覆盖掉了。

知道了原理我们来实现计分板功能。

4.2 实现

首先计分板的UI我还是用的房间界面的UI改一下。

先来理一下思路  —— 

  1. 当识别为本机玩家操作后,按住Tab键弹出该界面,松开关掉界面
  2. 计分板要获取房间内所有玩家信息:昵称、分数
  3. 当本机玩家射击击中其他玩家后,本机玩家分数自增
  4. 玩家分数更新后再次按下Tab键时要更新UI中的分数
  5. 当游戏房间中有玩家离开对应计分板也会删掉对应的玩家信息

PlayerController中 

   
    private int Score = 0;  //定义分数变量  ——  重点!!!!

    void Update()
    {
        //Debug.Log(photonView.Owner.NickName);
        //判断是否是本机玩家  只能操作本机角色  ——  重点!!!!
        if (photonView.IsMine)
        {
            if (isDie == true)
            {
                return;
            }
            UpdatePosition();
            UpdateRotation();
            //判断为本机玩家后执行按键操作方法  ——  重点!!!!
            InputCtl();
        }
        else
        {
            UpdateLogic();
        }
    }


    //角色操作
    public void InputCtl()
    {
        if (Input.GetMouseButtonDown(0))
        {
            //判断子弹个数
            if (gun.BulletCount > 0)
            {
                //如果正在播放填充子弹的动作不能开枪
                if (ani.GetCurrentAnimatorStateInfo(1).IsName("Reload"))
                {
                    return;
                }

                gun.BulletCount--;
                Game.uiManager.GetUI<FightUI>("FightUI").UpdateBulletCount(gun.BulletCount);
                //播放开火动画
                ani.Play("Fire", 1, 0);

                StopAllCoroutines();
                //开始执行攻击协同程序  ——  重点!!!!
                StartCoroutine(AttackCo());
            }
        }

        //退出游戏
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            Application.Quit();
        }
        
        //持续按下按键,查看计分板
        if (Input.GetKey(KeyCode.Tab))
        {
            //打开计分板界面  ——  重点!!!!
            Game.uiManager.ShowUI<ScoreboardUI>("ScoreboardUI");
            //执行更新分数方法 ——  重点!!!!
            Game.uiManager.ShowUI<ScoreboardUI>("ScoreboardUI").UpDateScore(); 

            // foreach (Player p in PhotonNetwork.PlayerList)
            // {
            //     Debug.Log("NickName:" + p.NickName);
            //     Debug.Log("GetScore:" + p.GetScore());
            // }
        }
        //当Tab键抬起
        else if(Input.GetKeyUp(KeyCode.Tab))
        {
            //关闭计分板界面  ——  重点!!!!
            Game.uiManager.CloseUI("ScoreboardUI");
        }

        if (Input.GetKeyDown(KeyCode.Q))
        {
            ani.Play("Grenade_Throw");
        }

        if (Input.GetKeyDown(KeyCode.R))
        {
            //填充子弹
            AudioSource.PlayClipAtPoint(reloadClip, transform.position); //播放填充子弹的声音
            ani.Play("Reload");
            gun.BulletCount = 10;
            Game.uiManager.GetUI<FightUI>("FightUI").UpdateBulletCount(gun.BulletCount);
        }
    }


    //攻击协同程序
    IEnumerator AttackCo()
    {
        //延迟0.1秒才发射子弹
        yield return new WaitForSeconds(0.1f);
        //播放射击音效
        AudioSource.PlayClipAtPoint(shootClip, transform.position);
        
        //获取本机玩家  ——  重点!!!!
        Player p = PhotonNetwork.LocalPlayer;
        
        //射线检测 鼠标中心点发送射线
        Ray ray = Camera.main.ScreenPointToRay(new Vector3(Screen.width * 0.5f, Screen.height * 0.5f,Input.mousePosition.z));
        //射线可以改成在枪口位置为起始点 发送,避免射线射到自身
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, 10000, LayerMask.GetMask("Player")))
        {
            Debug.Log("射到角色");
            //当本机玩家射中其他玩家时,把获取的本机玩家作为参数传递到GetHit方法中  ——  重点!!!!
            hit.transform.GetComponent<PlayerController>().GetHit(p);
        }

        photonView.RPC("AttackRpc", RpcTarget.All);  //所有玩家执行 AttackRpc 函数
    }

    [PunRPC]
    public void AttackRpc()
    {
        gun.Attack();
    }

    //同步所有角色受伤  p  ——  代表本机玩家
    public void GetHit(Player p)  
    {
        if (isDie == true)
        {
            return;
        }
        //同步所有角色受伤
        photonView.RPC("GetHitRPC", RpcTarget.All);
        //本机玩家得分自增并同步给服务器  ——  重点!!!!
        Score += 1;
        p.SetScore(Score);
    }

 在ScoreboardUI中,和RoomUI的脚本逻辑差不多

using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Pun.UtilityScripts;
using Photon.Realtime;
using UnityEngine.UI;

public class ScoreboardUI : MonoBehaviour
{
    Transform startTf; 
    Transform contentTf;
    GameObject roomPrefab;
    public List<ScoreItem> roomList;
    
    // Start is called before the first frame update
    void Awake()
    {
        roomList = new List<ScoreItem>();
        contentTf = transform.Find("bg/Content");
        //房间列表玩家成员
        roomPrefab = transform.Find("bg/roomItem").gameObject;

    }

    void Start()
    {
        //从服务器获取房间里的玩家项
        for (int i = 0; i < PhotonNetwork.PlayerList.Length; i++)
        {
            Player p = PhotonNetwork.PlayerList[i];
            CreateRoomItem(p);
        }
    }

    //生成玩家
    public void CreateRoomItem(Player p)
    {
        GameObject obj = Instantiate(roomPrefab, contentTf);
        obj.SetActive(true);
        ScoreItem item = obj.AddComponent<ScoreItem>();
        item.owerId = p.ActorNumber; 
        
        item.playerName = p.NickName;
        item.playerNameText(item.playerName);
        
        item.Score = p.GetScore();
        item.playerScoreText(item.Score);
        
        roomList.Add(item);
    }

   
    //执行更新房间内玩家分数的操作  ——  重点!!!!
    public void UpDateScore()
    {
        for (int i = 0; i < PhotonNetwork.PlayerList.Length; i++)
        {
            Player p = PhotonNetwork.PlayerList[i];
            ScoreItem item = roomList.Find((ScoreItem _item) => { return p.ActorNumber == _item.owerId; });
            if (item != null)
            {
                item.playerName = p.NickName;
                item.playerNameText(item.playerName);
        
                item.Score = p.GetScore();
                item.playerScoreText(item.Score);
                
                Debug.Log("NickName:" + p.NickName + "GetScore:" + p.GetScore());
                Debug.Log("::::::::::::::::::::::::::::::::::::::::::::::::::");
            }
        }
    }

    //删除离开房间的玩家
    public void DeleteRoomItem(Player p)
    {
        ScoreItem item = roomList.Find((ScoreItem _item) => { return p.ActorNumber == _item.owerId; });
        if (item != null)
        {
            Destroy(item.gameObject);
            roomList.Remove(item);
        }
    }
    
    //房间里的其他玩家离开房间
    public void OnPlayerLeftRoom(Player otherPlayer)
    {
        DeleteRoomItem(otherPlayer);
    }

    private void OnEnable()
    {
        PhotonNetwork.AddCallbackTarget(this);
    }

    private void OnDisable()
    {
        PhotonNetwork.RemoveCallbackTarget(this);
    }
}

ScoreItem的脚本用来把玩家信息和分数显示到计分板上

using UnityEngine;
using UnityEngine.UI;
using Photon.Pun;
using Photon.Pun.UtilityScripts;
using Photon.Realtime;

public class ScoreItem : MonoBehaviour
{
    public int owerId;  //玩家编号
    public int Score; //玩家分数
    public string playerName; //玩家名称
    
    public void playerNameText(string name)
    {
        transform.Find("Name").GetComponent<Text>().text = name; //PhotonNetwork.LocalPlayer.NickName;
    }
    
    public void playerScoreText(int score)
    {
        transform.Find("Score").GetComponent<Text>().text =  score.ToString();//PhotonNetwork.LocalPlayer.GetScore().ToString();
    }
}

 完成任务,真的很喜欢这个Demo,以后有时间还会继续优化的。今天先到这里,拜拜┏(^0^)┛

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【代码随想录 | 数组 03】有序数组的平方

文章目录 3.有序数组的平方3.1题目3.2思路3.2.1暴力解法3.2.2双指针法 3.有序数组的平方 3.1题目 977.有序数组的平方——力扣题目链接 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示…

Python 3.6.6安装方法(保留环境中python2不受影响)

前言&#xff1a;因为Linux系统下自带了python2的版本&#xff0c;所以我们要用Python3的话需要自己构建安装。并保证某些已经存在的服务可以正常使用python2。 具体步骤如下&#xff1a; 一、python3.6.6 安装 1.安装依赖包&#xff1a; yum -y install zlib zlib-devel yu…

借助资本力量创业:企业扩张能力、融资方式及创投公司投资条款的考量

在创业的道路上&#xff0c;借助资本的力量是许多企业实现快速扩张和持续发展的重要途径。然而&#xff0c;如何有效利用资本&#xff0c;确保企业在扩张过程中稳健前行&#xff0c;就需要创业者对企业扩张能力、融资方式以及创投公司的投资条款进行深入理解和审慎考量。 一、企…

LeetCode28.找出字符串中第一个匹配项

28.找出字符串中第一个匹配项 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 示例 1&#xff1a; 输入…

QT 如何在QPushButton上播放gif(终极版)

在平时浏览网站&#xff0c;或者使用软件的时候&#xff0c;经常可以见到&#xff1a;在点击了某个按钮之后&#xff0c;按钮上会显示动图以及提示文字。在QT中&#xff0c;比较常见且简单的做法就是&#xff1a;给按钮设置一个layout&#xff0c;然后在这个layout里面添加QLab…

ListBox显示图片的一些问题

相关&#xff1a;http://t.csdnimg.cn/xTnu8 显示图片的方案就是&#xff1a;自定义一个Photo类&#xff0c;里面有属性Source&#xff1b;View再绑定ViewModel中的Photo集合&#xff0c;再到View中给ListView设置数据模板 关键点&#xff1a;这样做很容易忘记写数据模板 数据…

4款实用性前端动画特效分享(附在线演示)

分享4款非常不错的项目动画特效 其中有jQuery特效、canvas特效、CSS动画等等 下方效果图可能不是特别的生动 那么你可以点击在线预览进行查看相应的动画特效 同时也是可以下载该资源的 全屏图片视差旋转切换特效 基于anime.js制作全屏响应式的图片元素布局&#xff0c;通过左…

docker部署在线音乐播放器

YesPlayMusic是一款高颜值的第三方网易云播放器 部署 下载镜像 docker pull fogforest/yesplaymusicdocker-compose部署 vim docker-compose.yaml version: 3 services:yesplaymusic:container_name: yesplaymusicimage: fogforest/yesplaymusicports:- 7950:80restart: a…

wxss和css的区别

目录 1. 语法差异 2. 尺寸单位 3. 样式导入 WXSS 示例代码&#xff1a; CSS 示例代码&#xff1a; 4. 组件和属性的支持 总结 WXSS (WeiXin Style Sheets) 和 CSS (Cascading Style Sheets) 都是用于描述文档样式的语言&#xff0c;但它们在微信小程序和网页开发中有一些…

数据结构从入门到精通——堆

堆 前言一、二叉树的顺序结构及实现 (堆&#xff09;1.1二叉树的顺序结构1.2堆的概念及结构 二、堆的练习题答案 三、堆的实现3.1堆向下调整算法3.2堆的创建3.3建堆时间复杂度3.4堆的插入3.5堆的删除3.6堆的代码实现 四、堆的具体实现代码Heap.hHeap.cTest.c堆的初始化堆的销毁…

二叉树相关题目

1.中序遍历和后序遍历构建二叉树&#xff1b; TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {//判空if(postorder.size() 0) return nullptr;//找到后序的最后元素就是根节点以及栈来存放数据auto rootnew TreeNode(postorder[post…

Hadoop大数据应用:Linux 部署 MapReduce 与 Yarn

目录 一、实验 1.环境 2.Linux 部署 MapReduce 3.Linux 部署 Yarn 4.Linux 调用大数据集群分析数据 二、问题 1.hadoop 的启动和停止命令 2.HDFS 使用命令 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构软件版本IP备注hadoop NameNode &#xf…

基于单片机的指纹采集识别系统设计

目 录 摘 要 I Abstract II 引 言 3 1 硬件选择与设计 5 1.1 总体设计及方案选择 5 1.1.1主控单片机选择 5 1.1.2传感器模块选择 6 1.1.3显示器模块选择 6 1.2 系统总体设计 7 2 系统硬件电路设计 8 2.1 系统主电路设计 8 2.1.1 主体电路设计 8 2.1.2 单片机最小系统设计 8 2.…

python的函数与类的定义

目录 1.函数 1.函数的定义 2.输入参数与输出参数的类型 3.输入和输出多个参数 1.普通参数 2.含有任意数量的参数 3.关键字参数 4.普通参数与多个参数的结合 2.类 1.类的定义 2.类的实例化 3.继承 1.函数 1.函数的定义 def 函数名(输入参数): 文档字符串 函数体 …

ElasticSearch深度分页问题如何解决

文章目录 概述解决方法深度分页方式from size深度分页之scrollsearch_after 三种分页方式比较 概述 Elasticsearch 的深度分页问题是指在大数据集上进行大量分页查询时可能导致的性能下降和资源消耗增加的情况。这种情况通常发生在需要访问大量数据的情形下&#xff0c;比如用…

finalshell连接cetOS7卡顿(配置完静态IP后出现的问题)

检查后的原因是:ssh服务端在连接时自动检测dns环境是否一致&#xff0c;这里将此次检测关闭即可 解决方案如下: vi /etc/ssh/sshd_config(打开后一直回车键到最下边)找到DNS&#xff0c;改为useDNS no&#xff08;默认为#useDNSyes&#xff09; 修改后重启服务&#xff1a; sys…

基于Java+SpringBoot+vue+element实现前后端分离玩具商城系统

基于JavaSpringBootvueelement实现前后端分离玩具商城系统 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文…

Pytorch入门实战 P2-CIFAR10彩色图片识别

目录 一、前期准备 1、数据集CIFAR10 2、判断自己的设备&#xff0c;是否可以使用GPU运行。 3、下载数据集&#xff0c;划分好训练集和测试集 4、加载训练集、测试集 5、取一个批次查看下 6、数据可视化 二、搭建简单的CNN网络模型 三、训练模型 1、设置超参数 2、编…

【Vue2】slot 插槽全家桶

插槽-默认插槽 插槽的基本语法 组件内需要定制的结构部分&#xff0c;改用<slot></slot>占位使用组件时, <MyDialog></MyDialog>标签内部, 传入结构替换slot给插槽传入内容时&#xff0c;可以传入纯文本、html标签、组件 插槽-默认值 封装组件时&am…

Nginx的日志怎么看,在哪看,access.log日志内容详解

Nginx 的日志文件通常位于服务器的文件系统中&#xff0c;具体位置可能因配置而异。以下是查看 Nginx 日志的几种方法&#xff1a; 1、查看访问日志&#xff1a;在默认配置下&#xff0c;Nginx 的访问日志文件路径为 /var/log/nginx/access.log。您可以通过命令 sudo cat /var…