unity制作FPS射击游戏

文章目录

  • 介绍
  • 鼠标移动控制视角
  • 行走、奔跑、跳跃、下蹲
  • 射击、后坐力、射速、瞄准、弹痕、枪火、抛壳
  • 手臂摇摆
  • 手枪
  • 切枪效果
  • 动画状态机
  • 玩家血量
  • 新地图
  • 场景颜色渐变
  • 激光墙
  • 获取钥匙
  • 滑动门
  • NPC属性
  • 攻击逻辑
  • 终点传送门


介绍

角色动作方面包括行走、奔跑、跳跃、武器切换、弹夹更换、武器展示、弹壳抛出效果、射击效果、全自动与半自动射击效果、瞄准效果、后坐力效果、弹痕效果等多种动作。

非玩家角色(NPC)具备多个动画状态,包括固定路径巡逻、行走、奔跑、寻路攻击等多种行为。

太空地图中拥有滑动门、激光枪、钥匙、传送门、电脑设备等多种功能性组件。

玩家可手持手枪或步枪,与NPC交火,取得钥匙,然后前往传送门以完成任务。在此过程中,游戏中丰富的特效将会呈现,包括玩家受伤特效、射击效果、钥匙获得特效、场景加载特效以及场景结束特效。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


鼠标移动控制视角

  1. 声明了鼠标灵敏度、玩家位置和摄像机旋转角度的变量。
  2. 在游戏开始时,锁定光标在窗口中心并隐藏。
  3. 在每帧更新中,根据鼠标移动量和灵敏度计算摄像机的旋转。
  4. 限制摄像机旋转在垂直方向上的角度,避免过度旋转。
  5. 将计算出的旋转应用于摄像机和玩家位置,实现视角控制。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 摄像机的旋转
/// 玩家左右旋转控制视线左右移动
/// 摄像机上下旋转控制视线上下移动
/// </summary>
public class MouseLook : MonoBehaviour
{
    public float mouseSensitivity=100f;//鼠标灵敏度

    public Transform playerBody;//玩家的位置
    private float xRotation=0f;

    // Start is called before the first frame update
    void Start()
    {
        //将光标锁定在该游戏窗口的中心,并且隐藏光标
        Cursor.lockState = CursorLockMode.Locked;
    }

    // Update is called once per frame
    void Update()
    {
        float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
        float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;

        xRotation -= mouseY;//将上下旋转的轴值进行累计
        xRotation = Mathf.Clamp(xRotation,-90f,90f);//限制轴值的累计(这里就能发现上90度和下90度角正好相对于了90的轴值)
        transform.localRotation = Quaternion.Euler(xRotation, 0f,0f);
        playerBody.Rotate(Vector3.up * mouseX);
    }
}


行走、奔跑、跳跃、下蹲

在这里插入图片描述

这脚本控制玩家的基本动作和声音效果:

  1. 变量和属性:

    • 定义了变量和属性,如移动速度、跳跃力度、重力、地面检测等。
  2. 移动和跳跃:

    • 使用Moveing()方法实现玩家移动,包括获取移动方向、用CharacterController.Move()移动、模拟跳跃和在空中减小高度。
  3. 下蹲:

    • 通过Crouch()方法修改CharacterController的高度实现下蹲。
  4. 声音效果:

    • 使用PlayFootStepSound()方法播放移动音效,根据行走和奔跑状态播放不同音效。
  5. 其他功能:

    • 检测是否在斜坡上,施加额外力量;检测是否在地面上。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 控制玩家移动
/// </summary>
public class PlayerMovement : MonoBehaviour
{
    private CharacterController characterController;
    public float walkSpeed = 10f;// 移动速度
    public float runSpeed=15f;//奔跑速度
    public float jumpForce = 3f;//跳跃力度
    private Vector3 velocity;//设置玩家Y轴的一个冲量变化
    private Vector3 moveDirction; //设置移动方向
    public float gravity = -9f; //设置重力

    public Transform groundCheck;//地面检测物体
    private float groundDistance = 0.4f;//与地面的距离
    public LayerMask groundMask;
    private bool isJump;//判断是否在跳跃
    private bool isGround;//判断是否在地面上
    public bool isWalk;//判断是否在行走
    public bool isRun;//判断是否在奔跑
    private bool isCrouch;//判断是否蹲下

    [SerializeField] private float slopeForce=6.0f; //走斜坡施加的力(是一个乘量)
    [SerializeField] private float slopeForceRayLength=2.0f; //斜坡射线长度(自定义量)

    [Header("键位设置")]
    [SerializeField] [Tooltip("跳跃按键")] private string jumpInputName = "Jump";
    [SerializeField] [Tooltip("奔跑按键")] private KeyCode runInputName;
    [SerializeField] [Tooltip("下蹲按键")] private KeyCode crouchInputName;

    private AudioSource audioSource;
    public AudioClip walkingSound;
    public AudioClip runingSound;

    void Start()
    {
        characterController = GetComponent<CharacterController>();
        audioSource = GetComponent<AudioSource>();
        audioSource.clip = walkingSound;
        audioSource.loop = true;
    }

    // Update is called once per frame
    void Update()
    {

        CheckGround();
        Moveing();
        Crouch();
    }

    /// <summary>
    /// 判断是否在斜坡上
    /// </summary>
    /// <returns></returns>
    public bool OnSlope()
    {
        if (isJump)
            return false;

        RaycastHit hit;
        //向下打出射线(检查是否在斜坡上)
        if (Physics.Raycast(transform.position, Vector3.down, out hit, characterController.height / 2 * slopeForceRayLength))
        {
            //如果触碰到的点的法线,不是在(0,1,0)这个方向上的,那么就人物处在斜坡上
            if (hit.normal != Vector3.up)
            {
                return true;
            }
        }
        return false;
    }


    /// <summary>
    /// 地面检测
    /// </summary>
    public void CheckGround() {
        //在 groundCheck 位置上做一个球体检测判断是否处在地面上
        isGround = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
        //如果处在地面上,重力设置成一个固定值
        if (isGround && velocity.y < 0)
        {
            velocity.y = -2f;
        }
    }

    /// <summary>
    /// 跳跃
    /// </summary>
    public void Jump() {
        isJump = Input.GetButtonDown(jumpInputName);
        //施加跳跃的力 
        if (isJump && isGround)
        {
            velocity.y = Mathf.Sqrt(jumpForce * -2f * gravity);
            //velocity.y = 20f;
        }
    }

    /// <summary>
    /// 下蹲
    /// </summary>
    public void Crouch() {
        isCrouch = Input.GetKey(crouchInputName);
        if (isCrouch)
        {
            characterController.height = 1f;
        }
        else
        {
            characterController.height =1.8f;
        }   
    }

    /// <summary>
    /// 移动
    /// </summary>
    public void Moveing()
    {
        float speed;
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
     
        isRun = Input.GetKey(runInputName);

        isWalk = (Mathf.Abs(h) > 0 || Mathf.Abs(v) > 0) ? true : false;
        speed = isRun ? runSpeed : walkSpeed; //设置行走或奔跑的速度

        moveDirction = (transform.right * h + transform.forward * v).normalized;//设置玩家移动方向(将移动速度进行规范化,防止斜向走速度变大)

        characterController.Move(moveDirction * speed * Time.deltaTime);//移动

        velocity.y += gravity * Time.deltaTime;//不在地面上(空中,累加重力值)
        characterController.Move(velocity * Time.deltaTime); //施加重力
        Jump();
        //如果处在斜面上移动
        if (OnSlope())
        {
            //向下增加力量
            characterController.Move(Vector3.down * characterController.height / 2 * slopeForce * Time.deltaTime);
        }
        PlayFootStepSound();



    }

    ///播放移动的音效
    public void PlayFootStepSound() {
        if (isGround && moveDirction.sqrMagnitude > 0.9f)
        {
            audioSource.clip = isRun ? runingSound : walkingSound;//设置行走或者奔跑的音效
            if (!audioSource.isPlaying)
            {
                audioSource.Play();
            }
        }
        else
        {
            if (audioSource.isPlaying)
            {
                audioSource.Pause();
            }
        }
    }

}


射击、后坐力、射速、瞄准、弹痕、枪火、抛壳

武器射击:控制射击位置、射程、子弹数量、射速、射击精度等参数,并播放相关音效、动画和特效。

武器装弹:控制子弹数量、弹匣容量、备弹数量、自动装弹、手动装弹等功能,并播放相关音效、动画和UI界面的更新。

武器切换:控制游戏中玩家切换主武器、副武器、全自动和半自动射击模式的功能,并更新UI界面的状态。

武器精度:根据射击模式(全自动或半自动)控制射击精度,实现游戏中的真实射击体验。

界面更新:控制UI界面的更新,包括弹匣数量、备弹数量、射击模式、准星等界面元素的实时更新。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// 武器射击
/// </summary>
public class WeaponController : MonoBehaviour
{
    public PlayerMovement PM;
    public Transform shooterPoint; // 射击的位置(枪口)
    public int range = 100; // 武器射程
    public int bulletsMag = 31; // 一个弹匣数量
    public int bulletLeft = 300; // 备弹
    public int currentBullets; // 当前子弹数

    public ParticleSystem muzzleFlash; // 枪口火焰特效
    public GameObject hitParticles; // 子弹击中粒子特效
    public GameObject bulletHole; // 弹孔
    public Light muzzleFlashLight; // 枪口火焰灯光

    public float fireRate = 0.1f; // 射速
    public float bulletdamage = 10.0f; // 单发子弹伤害
    private float fireTimer; // 计时器
    private float SpreadFactor; // 射击的一点偏移量

    [Header("键位设置")]
    [SerializeField] [Tooltip("填装子弹按键")] private KeyCode reloadInputName;
    [SerializeField] [Tooltip("查看武器按键")] private KeyCode inspectInputName;
    [SerializeField] [Tooltip("主武器按键")] private KeyCode AutoRifleKey;
    [SerializeField] [Tooltip("副武器按键")] private KeyCode HandGunKey;
    [SerializeField] [Tooltip("自动半自动切换按键")] private KeyCode GunShootModelInputName;

    private Animator anim;
    /*音效参数*/
    private AudioSource audioSource;
    public AudioClip AK47ShoundClip; /*枪声音效片段*/
    public AudioClip reloadAmmoLeftClip; // 换子弹1音效片段
    public AudioClip reloadOutOFAmmoClip; // 换子弹2音效片段(拉枪栓)

    private bool isReloading; // 判断是否在装弹
    private bool isAiming; // 判断是否在瞄准

    public Transform casingSpawnPoint; // 子弹壳抛出的位置
    public Transform casingPrefab; // 子弹壳预制体

    private Camera mainCamera;
    public ChooseGunController CGC; // 声明切换武器类的实例

    /*使用枚举区分全自动和半自动模式*/
    public enum ShootMode { AutoRifle, SemiGun };
    public ShootMode shootingMode;
    private bool GunShootInput; // 根据全自动和半自动 射击的键位输入发生改变
    private int modeNum = 1; // 模式切换的一个中间参数(1:全自动模式,2:半自动模式)
    private string shootModelName;

    /*UI的设置*/
    public Image crossHairUI;
    public Text ammoTextUI;
    public Text ShootModelTextUI;

    public Transform mainCameraTransform;
    public float recoilAmount = 2.0f; // 后坐力的强度
    public float recoilRecoverySpeed = 5.0f; // 后坐力恢复速度

    private Vector3 originalCameraPosition; // 原始相机位置,用于恢复后坐力
    private Quaternion originalCameraRotation;

    private void Start()
    {
        // 获取标签为"maincamera"的相机的Transform组件
        GameObject mainCameraObject = GameObject.FindGameObjectWithTag("MainCamera");
        if (mainCameraObject != null)
        {
            mainCameraTransform = mainCameraObject.transform;
            originalCameraPosition = mainCameraTransform.localPosition; // 记录原始相机位置
            originalCameraRotation = mainCameraTransform.localRotation;
        }

        audioSource = GetComponent<AudioSource>();
        anim = GetComponent<Animator>();
        currentBullets = bulletsMag;
        mainCamera = Camera.main;
        shootingMode = ShootMode.AutoRifle; // AK47步枪默认是全自动模式
        shootModelName = "AK47";
        UpdateAmmoUI();
    }

    private void Update()
    {
        if (health.isDead)
        {
            anim.SetBool("Run", false);
            anim.SetBool("Walk", false);
            anim.SetBool("Aim", false);
            return;
        }

        // 切换模式(全自动和半自动)
        if (Input.GetKeyDown(GunShootModelInputName) && modeNum != 1)
        {
            modeNum = 1;
            shootModelName = "全自动";
            shootingMode = ShootMode.AutoRifle;
            ShootModelTextUI.text = shootModelName;
        }
        else if (Input.GetKeyDown(GunShootModelInputName) && modeNum != 0)
        {
            modeNum = 0;
            shootModelName = "半自动";
            shootingMode = ShootMode.SemiGun;
            ShootModelTextUI.text = shootModelName;
        }

        /*控制射击模式的转换  后面就要用代码去动态控制了*/
        switch (shootingMode)
        {
            case ShootMode.AutoRifle:
                GunShootInput = Input.GetMouseButton(0);
                fireRate = 0.1f;
                break;
            case ShootMode.SemiGun:
                GunShootInput = Input.GetMouseButtonDown(0);
                fireRate = 0.2f;
                break;
        }

        if (GunShootInput && currentBullets > 0)
        {
            GunFire();
        }
        else
        {
            muzzleFlashLight.enabled = false;
        }

        // 计时器加时间
        if (fireTimer < fireRate)
        {
            fireTimer += Time.deltaTime;
        }

        anim.SetBool("Run", PM.isRun); // 播放跑步动画
        anim.SetBool("Walk", PM.isWalk);
        // 获取动画状态机第一层动画的状态
        AnimatorStateInfo info = anim.GetCurrentAnimatorStateInfo(0);
        // 两种换子弹的东湖
        if (info.IsName("reload_ammo_left") || info.IsName("reload_out_of_ammo"))
        {
            isReloading = true;
        }
        else
        {
            isReloading = false;
        }

        if (Input.GetKeyDown(reloadInputName) && currentBullets < bulletsMag && bulletLeft > 0)
        {
            Reload();
        }
        SpreadFactor = (isAiming) ? 0f : 0.01f;
        DoingAim();

        if (Input.GetKeyDown(inspectInputName))
        {
            anim.SetTrigger("Inspect");
        }
        // 切换主武器(自动步枪)
        if (Input.GetKeyDown(AutoRifleKey))
        {
            CGC.ChangeWeapon(0);
        }
        // 切换副武器(手枪)
        if (Input.GetKeyDown(HandGunKey))
        {
            CGC.ChangeWeapon(1);
        }

        if (mainCameraTransform != null)
        {
            mainCameraTransform.localPosition = Vector3.Lerp(mainCameraTransform.localPosition, originalCameraPosition, Time.deltaTime * recoilRecoverySpeed);
        }
    }

    // 更新UI
    public void UpdateAmmoUI()
    {
        ammoTextUI.text = currentBullets + " / " + bulletLeft;
        ShootModelTextUI.text = shootModelName;
    }

    /// <summary>
    /// 瞄准的逻辑
    /// </summary>
    public void DoingAim()
    {
        if (Input.GetMouseButton(1) && !isReloading && !PM.isRun)
        {
            isAiming = true;
            anim.SetBool("Aim", isAiming);
            crossHairUI.gameObject.SetActive(false);
            mainCamera.fieldOfView = 25; // 瞄准的时候摄像机视野变小
        }
        else
        {
            isAiming = false;
            anim.SetBool("Aim", isAiming);
            crossHairUI.gameObject.SetActive(true);
            mainCamera.fieldOfView = 60; // 瞄准的时候摄像机视野恢复
        }
    }

    /// <summary>
    /// 射击逻辑
    /// </summary>
    public void GunFire()
    {
        // 控制射速,当前弹夹打光了,正在装子弹,正在奔跑 就不可以发射了
        if (fireTimer < fireRate || currentBullets <= 0 || isReloading || PM.isRun) return;

        RaycastHit hit;
        Vector3 shootDirection = shooterPoint.forward;
        // 改成这个,shootDirection shooterPoint这个游戏物体进行小的偏移(TransformDirection 将local坐标转换为世界坐标)
        shootDirection = shootDirection + shooterPoint.TransformDirection(new Vector3(Random.Range(-SpreadFactor, SpreadFactor), Random.Range(-SpreadFactor, SpreadFactor)));

        if (Physics.Raycast(shooterPoint.position, shootDirection, out hit, range))
        {
            Debug.Log(hit.transform.name + "打到了");
            if (hit.transform.CompareTag("zombie"))
            {
                zombiehealth zombieHealth = hit.transform.GetComponent<zombiehealth>();
                if (zombieHealth != null)
                {
                    zombieHealth.TakeDamage(10f);
                }
                GameObject hitParticleEffect = Instantiate(hitParticles, hit.point, Quaternion.FromToRotation(Vector3.up, hit.normal));
                Destroy(hitParticleEffect, 1f);
            }
            else
            {
                GameObject hitParticleEffect = Instantiate(hitParticles, hit.point, Quaternion.FromToRotation(Vector3.up, hit.normal));
                Destroy(hitParticleEffect, 1f);
                GameObject bulletHoleEffect = Instantiate(bulletHole, hit.point, Quaternion.FromToRotation(Vector3.up, hit.normal));
                Destroy(bulletHoleEffect, 0.8f);
            }
            if (mainCameraTransform != null)
            {
                Vector3 recoilVector = Vector3.up * 0.3f;
                mainCameraTransform.localPosition += recoilVector;
            }
        }

        if (!isAiming)
        {
            anim.CrossFadeInFixedTime("fire", 0.1f); // 播放普通开火动画(使用动画的淡出淡入效果)
        }
        else
        {
            // 瞄准状态下,播放瞄准的开火动画
            anim.Play("aim_fire", 0, 0f);
        }
        muzzleFlash.Play(); // 播放火光特效
        muzzleFlashLight.enabled = true;
        PlayerShootSound(); // 播放射击音效
        // 实例抛弹壳
        Instantiate(casingPrefab, casingSpawnPoint.transform.position, casingSpawnPoint.transform.rotation);
        currentBullets--;
        UpdateAmmoUI();
        fireTimer = 0f; // 重置计时器
    }

    public void PlayerShootSound()
    {
        audioSource.clip = AK47ShoundClip;
        audioSource.Play();
    }

    /// <summary>
    /// 填装弹药逻辑
    /// </summary>
    public void Reload()
    {
        if (bulletLeft <= 0) return;
        DoReloadAnimation();

        // 计算需要填充的子弹
        int bulletToLoad = bulletsMag - currentBullets;
        // 计算备弹扣除的子弹
        int bulletToReduce = (bulletLeft >= bulletToLoad) ? bulletToLoad : bulletLeft;
        bulletLeft -= bulletToReduce; // 备弹减少
        currentBullets += bulletToReduce; // 当前子弹增加
        UpdateAmmoUI();
    }

    // 播放装弹动画
    public void DoReloadAnimation()
    {
        if (currentBullets > 0)
        {
            anim.Play("reload_ammo_left", 0, 0);
            audioSource.clip = reloadAmmoLeftClip;
            audioSource.Play();
        }

        if (currentBullets == 0)
        {
            anim.Play("reload_out_of_ammo", 0, 0);
            audioSource.clip = reloadOutOFAmmoClip;
            audioSource.Play();
        }
    }
}


手臂摇摆

这个脚本通过监听鼠标输入,在武器手臂模型的位置上添加摇摆效果,增加了武器的真实感和动态性。实现了武器摇摆效果,具体包括:

  1. 摇摆参数:定义了摇摆的幅度(amout)、平滑值(smoothAmout)和最大幅度(maxAmout)。

  2. 初始位置:记录武器初始位置。

  3. Start 函数:在开始时获取武器的初始位置。

  4. Update 函数:每帧更新,根据鼠标输入控制武器的手臂模型位置。

  5. 摇摆计算:根据鼠标的移动输入,计算出摇摆的偏移量。

  6. 限制范围:限制摇摆的偏移量在一定范围内。

  7. 位置更新:根据摇摆的偏移量和初始位置,平滑地更新武器的位置,实现摇摆效果。

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 武器摇摆
/// </summary>
public class WeaponSway : MonoBehaviour
{
    /*摇摆的参数*/
    public float amout; //摇摆幅度
    public float smoothAmout;//一个平滑值
    public float maxAmout;//最大摇摆幅度

    private Vector3 originPostion; //初始位置

    // Start is called before the first frame update
    void Start()
    {
        //自身位置(相对于父级物体变换得位置)
        originPostion = transform.localPosition;
    }

    // Update is called once per frame
    void Update()
    {
        //设置武器手臂模型位置得值,
        float movementX = -Input.GetAxis("Mouse X") * amout;
        float movementY = -Input.GetAxis("Mouse Y") * amout;
        //限制
        movementX = Mathf.Clamp(movementX, -maxAmout, maxAmout);
        movementY = Mathf.Clamp(movementY, -maxAmout, maxAmout);

        Vector3 finallyPostion = new Vector3(movementX, movementY, 0);
        //手柄位置变换
        transform.localPosition = Vector3.Lerp(transform.localPosition, finallyPostion + originPostion, Time.deltaTime * smoothAmout);
    }
}


手枪

这脚本实现了一个武器射击系统,包括:

  1. 武器属性:定义射程、弹匣容量等武器属性。
  2. 射击特效:创建火焰、粒子和弹孔特效。
  3. 射击模式:区分全自动和半自动射击,设置键位。
  4. 音效管理:播放射击和换弹音效。
  5. 瞄准与UI:按鼠标右键瞄准,显示准心和弹药数量。
  6. 射击逻辑:根据模式、键位和弹药数量触发射击。
  7. 装弹逻辑:播放动画、音效并填装弹药。
  8. 后坐力效果:模拟枪口抖动。
  9. 武器切换:按键切换主副武器。
  10. 更新UI:显示子弹数和射击模式。
  11. 瞄准逻辑:控制瞄准状态下视野和动画。

这些功能共同构建了玩家可以与武器进行交互的复杂系统。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class HandGunController : MonoBehaviour
{
    // 引用其他脚本和游戏对象
    public PlayerMovement PM;
    public Transform shooterPoint; // 武器射击的位置(枪口)

    // 武器参数
    public int range = 100; // 武器射程
    public int bulletsMag = 31; // 一个弹匣数量
    public int currentBullets; // 当前子弹数
    public int bulletLeft = 300; // 备弹

    // 枪口特效和音效
    public ParticleSystem muzzleFlash; // 枪口火焰特效
    public GameObject hitParticles; // 子弹击中粒子特效
    public GameObject bulletHole; // 弹孔
    public Light muzzleFlashLight; // 枪口火焰灯光
    public AudioClip HandGunSound; // 枪声音效片段
    public AudioClip reloadAmmoLeftClip; // 换子弹1音效片段
    public AudioClip reloadOutOFAmmoClip; // 换子弹2音效片段(拉枪栓)

    // 武器射速和键位设置
    public float fireRate = 0.1f; // 射速
    private float fireTimer; // 计时器
    private float SpreadFactor; // 射击的一点偏移量

    [SerializeField] private KeyCode reloadInputName; // 填装子弹按键
    [SerializeField] private KeyCode inspectInputName; // 查看武器按键
    [SerializeField] private KeyCode AutoRifleKey; // 主武器按键
    [SerializeField] private KeyCode HandGunKey; // 副武器按键
    [SerializeField] private KeyCode GunShootModelInputName; // 自动半自动切换按键

    // 控制器和状态
    private Animator anim; // 动画控制器
    private AudioSource audioSource; // 音效控制器
    private bool isReloading; // 是否在装弹
    private bool isAiming; // 是否在瞄准

    // 子弹壳抛出
    public Transform casingSpawnPoint; // 子弹壳抛出的位置
    public Transform casingPrefab; // 子弹壳预制体

    private Camera mainCamera; // 主摄像机
    public ChooseGunController CGC; // 切换武器类的实例

    // 射击模式和UI
    public enum ShootMode { AutoRifle, SemiGun }; // 射击模式枚举
    public ShootMode shootingMode; // 当前射击模式
    private bool GunShootInput; // 根据射击模式改变的射击键位输入
    private int modeNum = 0; // 模式切换的参数(1:全自动模式,2:半自动模式)
    private string shootModelName; // 射击模式名称

    // UI元素
    public Image crossHairUI; // 十字准心
    public Text ammoTextUI; // 弹药文本
    public Text ShootModelTextUI; // 射击模式文本

    private void Start()
    {
        audioSource = GetComponent<AudioSource>();
        anim = GetComponent<Animator>();
        currentBullets = bulletsMag;
        mainCamera = Camera.main;
        shootingMode = ShootMode.SemiGun; // G18手枪默认是半自动模式
        shootModelName = "clock";
        UpdateAmmoUI();
    }

    private void Update()
    {
        // 切换射击模式(全自动和半自动)
        if (Input.GetKeyDown(GunShootModelInputName) && modeNum != 1)
        {
            modeNum = 1;
            shootModelName = "全自动";
            shootingMode = ShootMode.AutoRifle;
            ShootModelTextUI.text = shootModelName;
        }
        else if (Input.GetKeyDown(GunShootModelInputName) && modeNum != 0)
        {
            modeNum = 0;
            shootModelName = "半自动";
            shootingMode = ShootMode.SemiGun;
            ShootModelTextUI.text = shootModelName;
        }

        // 根据射击模式确定射击输入和射速
        switch (shootingMode)
        {
            case ShootMode.AutoRifle:
                GunShootInput = Input.GetMouseButton(0);
                fireRate = 0.08f;
                break;
            case ShootMode.SemiGun:
                GunShootInput = Input.GetMouseButtonDown(0);
                fireRate = 0.2f;
                break;
        }

        // 射击逻辑
        if (GunShootInput && currentBullets > 0)
        {
            GunFire();
        }
        else
        {
            muzzleFlashLight.enabled = false;
        }

        // 计时器更新
        if (fireTimer < fireRate)
        {
            fireTimer += Time.deltaTime;
        }

        anim.SetBool("Run", PM.isRun);
        anim.SetBool("Walk", PM.isWalk);
        AnimatorStateInfo info = anim.GetCurrentAnimatorStateInfo(0);

        // 判断是否在换子弹动画中
        if (info.IsName("reload_ammo_left") || info.IsName("reload_out_of_ammo"))
        {
            isReloading = true;
        }
        else
        {
            isReloading = false;
        }

        // 换子弹逻辑
        if (Input.GetKeyDown(reloadInputName) && currentBullets < bulletsMag && bulletLeft > 0)
        {
            Reload();
        }
        SpreadFactor = (isAiming) ? 0f : 0.01f;
        DoingAim();

        // 查看武器动画
        if (Input.GetKeyDown(inspectInputName))
        {
            anim.SetTrigger("Inspect");
        }

        // 切换武器
        if (Input.GetKeyDown(AutoRifleKey))
        {
            CGC.ChangeWeapon(0); // 切换到主武器(自动步枪)
        }
        if (Input.GetKeyDown(HandGunKey))
        {
            CGC.ChangeWeapon(1); // 切换到副武器(手枪)
        }
    }

    // 更新UI
    public void UpdateAmmoUI()
    {
        ammoTextUI.text = currentBullets + " / " + bulletLeft;
        ShootModelTextUI.text = shootModelName;
    }

    // 瞄准逻辑
    public void DoingAim()
    {
        if (Input.GetMouseButton(1) && !isReloading && !PM.isRun)
        {
            isAiming = true;
            anim.SetBool("Aim", isAiming);
            crossHairUI.gameObject.SetActive(false);
            mainCamera.fieldOfView = 40;
        }
        else
        {
            isAiming = false;
            anim.SetBool("Aim", isAiming);
            crossHairUI.gameObject.SetActive(true);
            mainCamera.fieldOfView = 60;
        }
    }

    // 射击逻辑
    public void GunFire()
    {
        if (fireTimer < fireRate || currentBullets <= 0 || isReloading || PM.isRun) return;

        RaycastHit hit;
        Vector3 shootDirection = shooterPoint.forward;
        shootDirection = shootDirection + shooterPoint.TransformDirection(new Vector3(Random.Range(-SpreadFactor, SpreadFactor), Random.Range(-SpreadFactor, SpreadFactor)));

        if (Physics.Raycast(shooterPoint.position, shootDirection, out hit, range))
        {
            Debug.Log(hit.transform.name + "打到了");
            if (hit.transform.CompareTag("zombie"))
            {
                zombiehealth zombieHealth = hit.transform.GetComponent<zombiehealth>();
                if (zombieHealth != null)
                {
                    zombieHealth.TakeDamage(20f);
                }
                GameObject hitParticleEffect = Instantiate(hitParticles, hit.point, Quaternion.FromToRotation(Vector3.up, hit.normal));
                Destroy(hitParticleEffect, 1f);
            }
            else
            {
                GameObject hitParticleEffect = Instantiate(hitParticles, hit.point, Quaternion.FromToRotation(Vector3.up, hit.normal));
                Destroy(hitParticleEffect, 1f);
                GameObject bulletHoleEffect = Instantiate(bulletHole, hit.point, Quaternion.FromToRotation(Vector3.up, hit.normal));
                Destroy(bulletHoleEffect, 0.8f);
            }
        }

        if (!isAiming)
        {
            anim.CrossFadeInFixedTime("fire", 0.1f);
        }
        else
        {
            anim.Play("aim_fire", 0, 0f);
        }
        muzzleFlash.Play();
        muzzleFlashLight.enabled = true;
        PlayerShootSound();
        Instantiate(casingPrefab, casingSpawnPoint.transform.position, casingSpawnPoint.transform.rotation);
        currentBullets--;
        UpdateAmmoUI();
        fireTimer = 0f;
    }

    // 播放射击音效
    public void PlayerShootSound()
    {
        audioSource.clip = HandGunSound;
        audioSource.Play();
    }

    // 填装子弹逻辑
    public void Reload()
    {
        if (bulletLeft <= 0) return;
        DoReloadAnimation();

        int bulletToLoad = bulletsMag - currentBullets;
        int bulletToReduce = (bulletLeft >= bulletToLoad) ? bulletToLoad : bulletLeft;
        bulletLeft -= bulletToReduce;
        currentBullets += bulletToReduce;
        UpdateAmmoUI();
    }

    // 播放填装子弹动画
    public void DoReloadAnimation()
    {
        if (currentBullets > 0)
        {
            anim.Play("reload_ammo_left", 0, 0);
            audioSource.clip = reloadAmmoLeftClip;
            audioSource.Play();
        }

        if (currentBullets == 0)
        {
            anim.Play("reload_out_of_ammo", 0, 0);
            audioSource.clip = reloadOutOFAmmoClip;
            audioSource.Play();
        }
    }
}

在这里插入图片描述


切枪效果

这脚本实现了武器切换功能,主要包括:

  1. 武器集合:使用列表(List)存储多个武器游戏对象。

  2. 初始索引:在开始时初始化索引。

  3. 武器切换方法:根据传入的武器索引,控制显示对应的武器并隐藏其他武器。

  4. 循环遍历:遍历武器列表,根据索引设置武器的显示状态。

  5. 子武器处理:根据切换情况,更新对应子武器的弹药UI显示。

这个脚本通过列表管理多个武器,并根据切换情况动态显示和隐藏武器,实现了角色切换武器的功能。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 武器切换
/// </summary>
public class ChooseGunController : MonoBehaviour
{
    //武器设置为集合,存放多个武器
    public List<GameObject> Weapons=new List<GameObject>();
    private int index;

    // Start is called before the first frame update
    void Start()
    {
        index = 0;
    }

    //切换武器方法(全部武器挂载人物手上,默认隐藏,,谁需要就显示显示出来)
    public void ChangeWeapon(int WeaponIndex)
    {
        for (int i = 0; i < Weapons.Count; i++)
        {
            if (WeaponIndex == i)
            {
                Weapons[i].gameObject.SetActive(true);
                if (WeaponIndex == 0)
                {

                    Weapons[i].gameObject.GetComponentInChildren<WeaponController>().UpdateAmmoUI();      
                   // print(Weapons[i].gameObject.name);
                }
                else if (WeaponIndex == 1)
                {
                    Weapons[i].gameObject.GetComponentInChildren<HandGunController>().UpdateAmmoUI();
                    //print(Weapons[i].gameObject.name);
                }
            }
            else
            {
                Weapons[i].gameObject.SetActive(false);
            }
        }

    }

  
}


动画状态机

行走、奔跑、跳跃、开枪、换弹、切枪、瞄准

在这里插入图片描述


玩家血量

这脚本管理玩家的生命和死亡:

  • 有声音效果:受伤和死亡音效。
  • 跟踪生命值和死亡状态。
  • 控制死亡效果:播放音效、变暗场景、延迟后重载。
  • 当玩家受伤时,减少生命值和出血量。
  • 逐渐降低场景的颜色饱和度。
  • 如果玩家死亡,重新加载当前场景。
using UnityEngine;
using UnityStandardAssets.ImageEffects;
using UnityEngine.SceneManagement;

public class Health : MonoBehaviour
{
    public AudioClip hitSound;  // 受伤音效
    public AudioClip deathSound;  // 死亡音效
    public float maxHealth = 100f;  // 最大生命值
    public float currentHealth = 100f;  // 当前生命值
    private float timer = 0;  // 计时器

    public static bool isDead = false;  // 是否死亡

    private ColorCorrectionCurves colorCurves;  // 颜色校正曲线
    private MouseLook mouth;  // 鼠标观察

    private void Start()
    {
        BleedBehavior.BloodAmount = 0;  // 出血行为的血量
        colorCurves = Camera.main.GetComponent<ColorCorrectionCurves>();  // 获取颜色校正组件
        mouth = Camera.main.GetComponent<MouseLook>();  // 获取鼠标观察组件
    }

    void Update()
    {
        if (isDead)
        {
            LevelReset();  // 重置关卡
        }
    }

    // 受伤方法
    public void TakeDamage(float damage)
    {
        if (isDead)
        {
            return;  // 如果已经死亡,不处理伤害
        }
        
        currentHealth -= damage;  // 减少生命值

        if (currentHealth <= 0f)
        {
            Die();  // 死亡
        }
        else
        {
            currentHealth -= damage;
            AudioSource.PlayClipAtPoint(hitSound, transform.position);  // 播放受伤音效
        }
        
        BleedBehavior.BloodAmount += Mathf.Clamp01(damage / currentHealth);  // 增加出血量
        BleedBehavior.BloodAmount = 0.52f;  // 固定出血量(这一行可能需要调整或删除)
    }

    // 死亡方法
    private void Die()
    {
        isDead = true;  // 设置死亡状态
        AudioSource.PlayClipAtPoint(deathSound, transform.position);  // 播放死亡音效
        //this.GetComponent<PlayerMovement>().enabled = false;
        mouth.enabled = false;
        colorCurves.enabled = true;
        Invoke("ReloadCurrentScene", 6f);  // 延迟重载当前场景
    }

    // 重置关卡方法
    public void LevelReset()
    {
        //timer += Time.deltaTime;
        colorCurves.saturation -= (Time.deltaTime / 1.5f);  // 减少饱和度
        //colorCurves.saturation = Mathf.Max(0, colorCurves.saturation);
    }

    // 重新加载当前场景方法
    private void ReloadCurrentScene()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
        isDead = false;
    }
}


新地图

创建太空站地图。

在这里插入图片描述
在这里插入图片描述


场景颜色渐变

在这里插入图片描述

using UnityEngine;
using UnityEngine.UI;

public class FadeOut : MonoBehaviour
{
	public float speed = 1.0f;

	private Image image;
	private float alpha = 1.0f;
	
	public AudioClip enter;


	private void Start()
	{
		image = GetComponent<Image>();
		GetComponent<AudioSource>().PlayOneShot(enter);

	}

	private void Update()
	{
		alpha = Mathf.Lerp(alpha, 0.0f, speed * Time.deltaTime);
		image.color = new Color(image.color.r, image.color.g, image.color.b, alpha);
	}
}

激光墙

玩家通过激光墙会受到伤害。
给激光墙添加光源、空间音效。

在这里插入图片描述

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Laser : MonoBehaviour
{
    public int damage = 30;  // 伤害值
    public float damageDelay = 1f;  // 伤害延迟
    private float lastDamageTime = 0f;  // 上次伤害时间
    private GameObject player;  // 玩家对象

    void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player");  // 获取玩家对象
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject == player && Time.time > lastDamageTime + damageDelay)
        {
            player.GetComponent<Health>().TakeDamage(damage);  // 对玩家造成伤害
            lastDamageTime = Time.time;  // 更新上次伤害时间
        }
    }
}


获取钥匙

玩家获取钥匙才能打开后续的门。

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class card : MonoBehaviour
{
	public AudioClip keyGrab;
	private GameObject player;

    void Start()
    {
	    player = GameObject.FindGameObjectWithTag("Player");
    }
 
	void OnTriggerEnter(Collider other)
	{
		if (other.gameObject == player)
		{
			AudioSource.PlayClipAtPoint(keyGrab, transform.position);
			Destroy(this.gameObject);
		}
	}
}


滑动门

玩家触碰到门,门会打开。

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class door : MonoBehaviour
{
	private GameObject player;
	public AudioClip enter;
	public AudioClip exit;
	public float speed = 1f;
	private bool isOpen = false;
	private bool isMoving = false;
	private Vector3 targetPosition;

	private void Start()
	{
		player = GameObject.FindGameObjectWithTag("Player");
		//targetPosition = transform.position;
	}

	private void Update()
	{
		if (isMoving)
		{
			// 修复:更新门的位置而不是碰撞体的位置
			this.gameObject.transform.position = Vector3.Lerp(transform.position, targetPosition, speed * Time.deltaTime);

			if (Vector3.Distance(transform.position, targetPosition) < 0.01f)
			{
				isMoving = false;
			}
		}
	}

	private void OnTriggerEnter(Collider other)
	{
		if (other.gameObject == player && !isOpen)
		{
			isOpen = true;
			targetPosition = new Vector3(transform.position.x, 5.3f, transform.position.z);
			AudioSource.PlayClipAtPoint(enter, transform.position);
			isMoving = true;
		}
	}

	private void OnTriggerExit(Collider other)
	{
		if (other.gameObject == player && isOpen)
		{
			isOpen = false;
			targetPosition = new Vector3(transform.position.x, 1f, transform.position.z);
			AudioSource.PlayClipAtPoint(exit, transform.position);
			isMoving = true;
		}
	}
}


NPC属性

在这里插入图片描述

  1. Start(): 在脚本启动时进行初始化,获取组件引用、设置初始参数、获取玩家对象,禁用导航代理,获取动画控制器。

  2. Update(): 在每帧更新中处理椭圆运动、朝向、接近原始位置的计算,以及判断玩家是否在视野范围内,根据情况设置移动方式和动画。

  3. OnTriggerEnter(Collider other): 当碰撞体进入触发器范围时,检查碰撞对象标签是否为玩家,如果是,设置攻击动画、播放音效,并对玩家造成伤害。

  4. OnTriggerExit(Collider other): 当碰撞体离开触发器范围时,检查碰撞对象标签是否为玩家,如果是,恢复奔跑动画。

脚本实现了僵尸的椭圆运动、追踪玩家、攻击玩家等基本逻辑。

using UnityEngine;
using UnityEngine.AI;

public class zombie : MonoBehaviour
{
	public float distance = 5f;  // 移动距离
	public float speed = 1f;  // 移动速度
	public float eccentricity = 0.8f;  // 离心率
	public float rotationSpeed = 5f;  // 旋转速度
	public float scale = 1f;  // 移动倍率
	public float maxDistance = 5f; // 最大距离,当玩家距离小于该值时,设置isInSight为true
	public int damage = 30;

	private Vector3 startPosition;
	private float elapsedTime = 0f;

	private GameObject player;
	private bool isInSight ;
	public AudioClip Sound;
	public AudioClip bit;
	private Animator zombieanimator;
	private NavMeshAgent agent;
	

	public 	bool isEllipseMovementEnabled ; // 是否允许椭圆运动
	public  bool canmove ; // 是否允许椭圆运动
	public zombiehealth zomhealth;

	private void Start()
	{
		zomhealth=this.GetComponent<zombiehealth>();
		isInSight = false;
		isEllipseMovementEnabled = true;
		canmove = false;
		startPosition = transform.position;
		player = GameObject.FindGameObjectWithTag("Player");
		agent = GetComponent<NavMeshAgent>();
		agent.enabled = false;
		zombieanimator = GetComponent<Animator>();
	}

	private void Update()
	{
		if (isEllipseMovementEnabled&&!zomhealth.isDead)
		{
			elapsedTime += Time.deltaTime * speed;

			// 根据参数计算椭圆轨迹上的位置
			float x = distance * Mathf.Cos(elapsedTime * scale);
			float z = distance * eccentricity * Mathf.Sin(elapsedTime * scale);

			Vector3 targetPosition = startPosition + new Vector3(x, 0f, z);

			// 平滑移动
			transform.position = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime * speed);

			// 计算椭圆曲线上的切线向量
			float dx = -distance * scale * Mathf.Sin(elapsedTime * scale);
			float dz = distance * eccentricity * scale * Mathf.Cos(elapsedTime * scale);
			Vector3 tangent = new Vector3(dx, 0f, dz).normalized;

			// 计算平滑的旋转
			Quaternion targetRotation = Quaternion.LookRotation(tangent, Vector3.up);
			transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, Time.deltaTime * rotationSpeed);

			// 检查是否接近原始位置
			float distanceToStart = Vector3.Distance(transform.position, startPosition);

			if (distanceToStart < 0.1f)
			{
				// 返回原始位置,重置时间
				elapsedTime = 0f;
			}
		}

		if (!isInSight)
		{
			float playerDistance = Vector3.Distance(transform.position, player.transform.position);

			if (playerDistance < maxDistance&&!zomhealth.isDead)
			{
				isEllipseMovementEnabled = false; // 停止椭圆运动
				agent.enabled = true;
				canmove=true;
				isInSight = true;
				AudioSource.PlayClipAtPoint(Sound, transform.position);
				zombieanimator.SetBool("run",true);
			}
		}
		
		if(canmove){
			agent.SetDestination(player.gameObject.transform.position);}
	}
	
	void OnTriggerEnter(Collider other)
	{
		if (other.gameObject.tag == "Player")
		{
			//	zombieanimator.SetBool("run",false);

			zombieanimator.SetBool("attack",true);
			AudioSource.PlayClipAtPoint(bit, transform.position);
			player.GetComponent<health>().TakeDamage(damage);

		}
	}
	void OnTriggerExit(Collider other)
	{
		if (other.gameObject.tag == "Player")
		{
			zombieanimator.SetBool("run",true);
			zombieanimator.SetBool("attack",false);
			//zombieanimator.SetBool("attack",true);

		}
	}
	
}


攻击逻辑

玩家开枪能对怪兽造成伤害,怪兽接触到玩家也能造成伤害,这脚本管理了僵尸的生命和死亡。

在这里插入图片描述

  1. 生命管理:

    • 跟踪最大生命值和当前生命值。
    • 接收伤害并减少生命值,如果已死亡则不再处理。
  2. 死亡效果:

    • 播放死亡声音,禁用移动和导航代理。
    • 设置死亡动画,1.5秒后销毁僵尸对象。
using UnityEngine;
using UnityEngine.AI;

public class zombiehealth : MonoBehaviour
{
    public AudioClip deathSound;        // 死亡时播放的声音
    public float maxHealth = 100f;       // 僵尸的最大生命值
    public float currentHealth;          // 当前生命值
    public bool isDead;                  // 僵尸是否已死亡
    private NavMeshAgent agent;          // 导航网格代理组件的引用
    private Animator zombieanimator;     // 动画控制器组件的引用
    public zombie zom;                   // 僵尸脚本的引用

    private void Start()
    {
        zom = this.GetComponent<zombie>();                  // 获取僵尸脚本组件
        isDead = false;                                     // 初始化死亡状态为否
        currentHealth = maxHealth;                          // 设置初始生命值
        agent = GetComponent<NavMeshAgent>();               // 获取导航网格代理组件
        zombieanimator = GetComponent<Animator>();          // 获取动画控制器组件
    }

    public void TakeDamage(float damage)
    {
        if (isDead)
        {
            return;                                         // 如果已死亡,退出函数
        }

        currentHealth -= damage;                            // 减少生命值

        if (currentHealth <= 0f)
        {
            Die();                                          // 如果生命值小于等于0,触发死亡
        }
        else
        {
            currentHealth -= damage;                        // 多余的减少生命值操作
        }
    }

    private void Die()
    {
        GetComponent<AudioSource>().PlayOneShot(deathSound); // 播放死亡声音
        isDead = true;                                      // 设置死亡状态为真
        zom.canmove = false;                                // 禁用僵尸移动
        agent.enabled = false;                              // 禁用导航网格代理
        zombieanimator.SetBool("dead", true);               // 在动画控制器中设置"dead"参数为真
        Destroy(this.gameObject, 1.5f);                     // 1.5秒后销毁僵尸对象
    }
}


终点传送门

在这里插入图片描述
这脚本实现了玩家离开游戏场景的效果:

  1. 声音与特效:

    • 定义退出声音(ex)和退出音乐(exitmusic)。
    • 获取玩家对象和主摄像机的色彩校正曲线特效(ColorCorrectionCurves)组件。
  2. 重置场景:

    • 在离开触发区域后,增加色彩饱和度,逐渐变暗场景。
    • 播放退出声音和音乐,延迟后重新加载当前场景。
  3. 场景重载:

    • 重新加载当前游戏场景。

这个脚本通过渐变色彩和播放音效,为玩家离开游戏场景创造了一个独特的效果。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityStandardAssets.ImageEffects;

public class exit : MonoBehaviour
{
	public AudioClip ex;
	
	private GameObject player;
	
	public float delayTime=5f;
	private ColorCorrectionCurves colorCurves;
	
	private bool isend=false;
	public AudioClip exitmusic;

	
	
	// Start is called before the first frame update
	void Start()
	{
		player = GameObject.FindGameObjectWithTag("Player");
		colorCurves = Camera.main.GetComponent<ColorCorrectionCurves>();
	}


	void Update()
	{
		if (isend)
		{
			LevelReset();
		}
	}
   
	public void LevelReset()
	{
		//timer += Time.deltaTime;
		colorCurves.saturation += (Time.deltaTime);
		colorCurves.saturation = Mathf.Max(0, colorCurves.saturation);
	}
   
	void OnTriggerEnter(Collider other)
	{
		if (other.gameObject == player)
		{
			isend=true;
			colorCurves.enabled=true;
			AudioSource.PlayClipAtPoint(ex, transform.position);

			Invoke("playexitmusic", 1.5f);
			Invoke("ReloadCurrentScene", delayTime);
		}
	}
	
	private void ReloadCurrentScene()
	{
		SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
	}
	
	private void playexitmusic()
	{
		AudioSource.PlayClipAtPoint(exitmusic, transform.position);
	}
}



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

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

相关文章

科技引领,教育革新|EasyV助力数字孪生智慧教育建设!

数字孪生校园是以物联网、大数据、云计算、人工智能、三维可视化等新型数字化技术为基础&#xff0c;构建的数智校园的“大脑”。对校园的人、车、资产设施、各业务系统进行全联接&#xff0c;实现数据全融合、状态全可视、业务全可管、事件全可控&#xff0c;使校园更安全、更…

elasticSearch常见的面试题

常见的面试问题 描述使用场景 es集群架构3个节点&#xff0c;根据不同的服务创建不同的索引&#xff0c;根据日期和环境&#xff0c;平均每天递增60*2&#xff0c;大约60Gb的数据。 调优技巧 原文参考&#xff1a;干货 | BAT等一线大厂 Elasticsearch面试题解读 - 掘金 设计阶…

【《快速构建AI应用——AWS无服务器AI应用实战》——基于云的解决方案快速完成人工智能项目的指南】

基于云的人工智能服务可以自动完成客户服务、数据分析和财务报告等领域的各种劳动密集型任务。其秘诀在于运用预先构建的工具&#xff0c;例如用于图像分析的Amazon Rekognition或用于自然语言处理的AWS Comprehend。这样&#xff0c;就无须创建昂贵的定制软件系统。 《快速构…

PADS过孔操作

过孔须先在Layout内设置好类型&#xff0c;然后在“过孔配置”选项页将使用的过孔勾选。 2&#xff09;有多个过孔类型&#xff0c;可以先指定当前设计时使用的过孔类型。布线操作期间&#xff0c;右击在“过孔类型”选项内选择“通孔类过孔”或者“自动类过孔”&#xff0c;选…

探索产品项目管理软件的种类及功能

随着科技的不断发展&#xff0c;越来越多的企业开始重视产品项目管理的重要性。产品项目管理软件作为一种有效的工具&#xff0c;可以帮助企业更好地规划、执行和控制项目&#xff0c;提高项目的成功率。本文将分为两部分&#xff0c;分别介绍产品项目管理软件的功能以及一些知…

MySQL数据库安装(二)

夕阳留恋的不是黄昏&#xff0c;而是朝阳 上一章简单介绍了MySQL数据库概述(一), 如果没有看过, 请观看上一章 一. MySQL 卸载 一.一 停止MySQL服务 在卸载之前&#xff0c;先停止MySQL8.0的服务。按键盘上的“Ctrl Alt Delete”组合键&#xff0c;打开“任务管理器”对话…

Ubuntu服务器ELK部署与实践

文章目录 1. Docker安装2. 拉镜象2.1 ElastciSearch2.2 Kibana2.3 logstash 3. 数据展示 1. Docker安装 看之前的文章 docker ubuntu完全卸载docker及再次安装 Ubuntu安装 Docker 此外&#xff0c;Docker偶尔会出现这种问题dial tcp: lookup registry-1.docker.io on 192.168.1…

React 之 Redux - 状态管理

一、前言 1. 纯函数 函数式编程中有一个非常重要的概念叫纯函数&#xff0c;JavaScript符合函数式编程的范式&#xff0c;所以也有纯函数的概念 确定的输入&#xff0c;一定会产生确定的输出 函数在执行过程中&#xff0c;不能产生副作用 2. 副作用 表示在执行一个函数时&a…

基于Java+SpringBoot+SpringCloud+Vue的智慧养老平台设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

C++入门篇6 C++的内存管理

在学习C的内存管理之前&#xff0c;我们先来回顾一下C语言中动态内存 int main() {int* p1 (int*)malloc(sizeof(int));free(p1);// 1.malloc/calloc/realloc的区别是什么&#xff1f;int* p2 (int*)calloc(4, sizeof(int));//calloc 可以初始化空间为0int* p3 (int*)reall…

Set-up ESP-AT Environment on Windows using CMD

Before you start, the following environments need to be installed: Git BashPython environment, suggest Python version: 3.8.7. Please ensure the installation of Python v3.8 version environment, and remember to select the option “add to PATH” during the in…

TCP Socket 基础知识点(实例是以Java进行演示)

本篇根据TCP & Socket 相关知识点和学习所得进行整理所得。 文章目录 前言1. TCP相关知识点1.1 双工/单工1.2 TCP协议的主要特点1.3 TCP的可靠性原理1.4 报文段1.4.1 端口1.4.2 seq序号1.4.3 ack确认号1.4.4 数据偏移1.4.5 保留1.4.6 控制位1.4.7 窗口1.4.8 校验和1.4.9 紧…

无人机管控平台,推动电力巡检管理水平提升

各地区无人机作业水平和管理水平存在参差不齐&#xff0c;电力巡检管理要求与业务发展水平不匹配的问题。同时&#xff0c;巡检数据的存储和管理分散&#xff0c;缺乏有效的整合与共享手段&#xff0c;使得内外业脱节&#xff0c;没有形成统一应用和闭环管理。这就导致巡检数据…

机器学习、人工智能、深度学习三者的区别

目录 1、三者的关系 2、能做些什么 3、阶段性目标 1、三者的关系 机器学习、人工智能&#xff08;AI&#xff09;和深度学习之间有密切的关系&#xff0c;它们可以被看作是一种从不同层面理解和实现智能的方法。 人工智能&#xff08;AI&#xff09;&#xff1a;人工智能是一…

springboot+maven插件调用mybatis generator自动生成对应的mybatis.xml文件和java类

mybatis最繁琐的事就是sql语句和实体类&#xff0c;sql语句写在java文件里很难看&#xff0c;字段多的表一开始写感觉阻力很大&#xff0c;没有耐心&#xff0c;自动生成便成了最称心的做法。自动生成xml文件&#xff0c;dao接口&#xff0c;实体类&#xff0c;虽一直感觉不太优…

路由表、转发表

文章目录 1.路由表1.1.查询路由表的开销 2.转发表3.两个表的关系3.1.联系3.2.区别 4.误区5.区分二表的好处之实例6.Linux中通过NAT原理配置转发表7.优势8、转发表与MAC表9、IP VS MAC 1.路由表 路由信息最终要存储在用于路由器的主机或者专业路由器上&#xff0c;存放这些信息…

Linux操作系统块设备参数调优

目录 一、队列深度 二、调度算法 三、预读量 四、I/O对齐 一、队列深度 队列深度决定了给块设备写I/O的最大并发数&#xff0c;对于Linux系统&#xff0c;默认值为128&#xff0c;一般情况下不建议用户修改此参数。用户可以使用cat命令查询当前块设备队列深度。 linux-ob3a…

kubernetes集群日志管理系统部署方案

安装前请下载各种所需yaml文件 1、安装 elasticsearch 组件 1.1 创建名称空间 #elasticsearch、fluentd、kibana都会安装到此空间下 kubectl apply -f kube-logging.yaml1.2 查看 kube-logging 名称空间是否创建成功 kubectl get namespaces | grep kube-logging[rootk8s-…

全球数据泄露事件增加近三倍

网络安全公司 Surfshark 的最新研究显示&#xff0c;2023 年第二季度共有 1.108 亿个账户遭到泄露&#xff0c;其中美国排名第一&#xff0c;几乎占 4 月至 6 月所有泄露事件的一半。 俄罗斯排名第二&#xff0c;西班牙排名第三&#xff0c;其次是法国和土耳其。 与 2023 年…

3d虚拟vr汽车实景展厅吸引更多潜在消费者

随着人们对生活品质的追求&#xff0c;越来越多的消费者开始关注汽车的外观设计、内饰配置等方面。传统的展示方式已经不能满足消费者的需求&#xff0c;车辆VR虚拟漫游展示应运而生。借助VR虚拟现实和web3d开发建模技术&#xff0c;对汽车的外观、造型及信息数据进行数字化处理…