【Unity从零开始制作空洞骑士】①制作人物的移动跳跃转向以及初始的动画制作

2023-11-15

事情的起因:

  首先我之前在b站的时候突然发现有个大佬说复刻了空洞骑士,点进去一看发现很多场景都福源道非常详细,当时我除了觉得大佬很强的同时也想自己试一下,而且当时对玩家血条设计等都很模糊,就想着问up主,结果因为制作的时间过了很久了,大佬也有些答不上来,于是我就先下来,然后一直跟着其它视频继续学,这几天闲着就试着通过大佬的代码能不能逐步做一个空洞骑士的mod出来,所幸前面的步骤都比较顺利,通过大佬的代码还是能慢慢做出来

(Steam截图镇个楼)

学习目标:

大佬的视频以及Github源码:

【Unity3D】空洞骑士の复刻_哔哩哔哩_bilibili

项目开源:https://github.com/dreamCirno/Hollow-Knight-Imitation


学习内容:

初始工作就先创建一个2D项目,然后本项目需要准备的插件有点多,把没必要的插件删除后就这些了,ProCamera2D,Input system,Post Poccessing,PlayerMaker(这个我没买)

打开开源项目,先别一次性把Assets的项目全部导入,不然肯定一堆报错的,我们先把角色的精灵图导入,然后再拖入几个地板,然后场景就暂时这样了。 

接着我们要为玩家创建动作了。

创建Input Actions命名为InputControl,然后这些都是老操作了。

 

然后就生成一个C#脚本名字就叫InputControl,然后创建一个名字叫InputManger的空对象以及一个同名脚本、

我们暂时只用到GamePlayer的动作表所以就先这样写了。 

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

public class InputManager : MonoBehaviour
{
    private static InputControl inputControl;
    public static InputControl InputControl
    {
        get
        {
            if(inputControl == null)
            {
                inputControl = new InputControl();
            }
            return inputControl;
        }
    }

    private void OnEnable()
    {
        InputControl.GamePlayer.Movement.Enable();
        InputControl.GamePlayer.Jump.Enable();
        InputControl.GamePlayer.Attack.Enable();
    }

    private void OnDisable()
    {
        InputControl.GamePlayer.Movement.Disable();
        InputControl.GamePlayer.Jump.Disable();
        InputControl.GamePlayer.Attack.Disable();
    }



}

 

玩家类脚本:

  我们为我们的Player创建一个名字叫CharacterController2D的脚本。

然后为我们的Player对象添加上组件

2D物理材质如下

首先我们先实现玩家的移动和转向

对于移动我们采用InputSystem对于行为动作的订阅事件和退订事件,用vectorInput读入键盘的输入,

对于转向则根据任务面部朝向,当向右移动的时候transform.localScale为(-1,1,1),向左则为(1,1,1);

using Com.LuisPedroFonseca.ProCamera2D;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class CharacterController2D : MonoBehaviour
{
    #region Propertries
    readonly Vector3 flippedScale = new Vector3(-1, 1, 1);

    private Rigidbody2D controllerRigibody;

    [Header("依赖脚本")] Animator animator;

    [Header("移动参数")]
    [SerializeField] float maxSpeed = 0.0f;
    [SerializeField] float maxGravityVelocity = 10.0f;
    [SerializeField] float jumpForce = 0.0f;
    [SerializeField] float groundedGravityScale = 0.0f;

    [SerializeField] float jumpGravityScale = 0.0f;
    [SerializeField] float fallGravityScale = 0.0f;

    private Vector2 vectorInput;
    private int jumpCount;
    private bool JumpInput;
    private float counter;

    private bool enableGravity;
    private bool canMove;

    private bool isOnGround;
    private bool isFacingLeft;
    private bool isJumping;
    private bool isFalling;

    private int animatorFirstLandingBool;
    private int animatorGroundedBool;
    private int animatorMovementSpeed;
    private int animatorVelocitySpeed;
    private int animatorJumpTrigger;
    private int animatorDoubleJumpTrigger;

    [Header("其它参数")]
    [SerializeField] private bool firstLanding;

    #endregion

    #region CallBackFunctions
    private void Awake()
    {
        controllerRigibody = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();
    }

    private void OnEnable()
    {
        InputManager.InputControl.GamePlayer.Movement.performed += ctx => vectorInput = ctx.ReadValue<Vector2>();
        InputManager.InputControl.GamePlayer.Jump.started += Jump_Started;
        InputManager.InputControl.GamePlayer.Jump.performed += Jump_Performed;
        InputManager.InputControl.GamePlayer.Jump.canceled += Jump_Canceled;
    }

    private void OnDisable()
    {
        InputManager.InputControl.GamePlayer.Movement.performed -= ctx => vectorInput = ctx.ReadValue<Vector2>();
        InputManager.InputControl.GamePlayer.Jump.started -= Jump_Started;
        InputManager.InputControl.GamePlayer.Jump.performed -= Jump_Performed;
        InputManager.InputControl.GamePlayer.Jump.canceled -= Jump_Canceled;
    }

    private void Start()
    {
        animatorFirstLandingBool = Animator.StringToHash("FirstLanding");
        animatorGroundedBool = Animator.StringToHash("Grounded");
        animatorVelocitySpeed = Animator.StringToHash("Velocity");
        animatorMovementSpeed = Animator.StringToHash("Movement");
        animatorJumpTrigger = Animator.StringToHash("Jump");
        animatorDoubleJumpTrigger = Animator.StringToHash("DoubleJump");

        animator.SetBool(animatorFirstLandingBool, firstLanding);

        enableGravity = true;
        canMove = true;
    }

    private void FixedUpdate()
    {
        UpdateVelocity();
        UpdateDirection();

    }

    #endregion

    #region Movement

    private void UpdateVelocity()
    {
        Vector2 velocity = controllerRigibody.velocity;
        if (vectorInput.x != 0)
        {
            velocity.y = Mathf.Clamp(velocity.y, -maxGravityVelocity / 2, maxGravityVelocity / 2);
        }
        else
        {
            velocity.y = Mathf.Clamp(velocity.y, -maxGravityVelocity, maxGravityVelocity);
        }
        animator.SetFloat(animatorVelocitySpeed, controllerRigibody.velocity.y);
        if (canMove)
        {
            controllerRigibody.velocity = new Vector2(vectorInput.x * maxSpeed, velocity.y);
            animator.SetInteger(animatorMovementSpeed, (int)vectorInput.x);
        }
    }

    private void UpdateDirection()
    {
        //控制玩家的旋转
        if (controllerRigibody.velocity.x > 1f && isFacingLeft)
        {
            isFacingLeft = false;
            transform.localScale = flippedScale;
        }
        else if (controllerRigibody.velocity.x < -1f && !isFacingLeft)
        {
            isFacingLeft = true;
            transform.localScale = Vector3.one;
        }
    }

   
    

    private void UpdateGrounding(Collision2D collision,bool exitState)
    {
        if (exitState)
        {
            if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian") || collision.gameObject.layer == LayerMask.NameToLayer("Soft Terrian"))
            {
                isOnGround = false;

            }
        }
        else
        {   
//判断为落地状态
            if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian")
                || collision.gameObject.layer == LayerMask.NameToLayer("Soft Terrian")
                && collision.contacts[0].normal == Vector2.up
                && !isOnGround)
            {
                isOnGround = true;
                isJumping = false;
                isFalling = false;
            }
            //判断为头顶碰到物体状态
            else if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian") || collision.gameObject.layer == LayerMask.NameToLayer("Soft Terrian")
                && collision.contacts[0].normal == Vector2.down && isJumping)
            {

            }
        }
        animator.SetBool(animatorGroundedBool, isOnGround);
    }

    public void StopHorizontalMovement()
    {
        Vector2 velocity = controllerRigibody.velocity;
        velocity.x = 0;
        controllerRigibody.velocity = velocity;
        animator.SetInteger(animatorMovementSpeed, 0);
    }

    public void SetIsOnGrounded(bool state)
    {
        isOnGround = state;
        animator.SetBool(animatorGroundedBool, isOnGround);
    }
    #endregion

    #region Combat
    private void Jump_Canceled(InputAction.CallbackContext context)
    {
        
    }

    private void Jump_Performed(InputAction.CallbackContext context)
    {
       
    }

    private void Jump_Started(InputAction.CallbackContext context)
    {
        
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        UpdateGrounding(collision, false);
    }

    private void OnCollisionStay2D(Collision2D collision)
    {
        UpdateGrounding(collision, false);
    }

    private void OnCollisionExit2D(Collision2D collision)
    {
        UpdateGrounding(collision, true);
    }
    #endregion

    #region Others

    public void FirstLanding()
    {

    }

    #endregion

}

接着我们制作动画,制作好Idle,walk,Run的动画

 

 

 

 

 

 

由于我们还没为动画判断条件Grounded作代码判断条件,所以就先创建一个空对象用于地面检测

 

 再给他一个脚本

using UnityEngine;

public class GroundDetector : MonoBehaviour
{
    private CharacterController2D character;

    private void Awake()
    {
        character = FindObjectOfType<CharacterController2D>();
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian"))
        {
            character.SetIsOnGrounded(true);
        }
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian"))
        {
            character.SetIsOnGrounded(false);
        }
    }
}

 移动的脚本做完了我们还需要做跳跃,跳跃分为一段跳和二段跳,首先打开CharacterController2D,我们将通过跳跃计数器决定播放一段跳或是二段跳的动画,并通过判断条件决定什么时候重置动画

using Com.LuisPedroFonseca.ProCamera2D;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class CharacterController2D : MonoBehaviour
{
    #region Propertries
    readonly Vector3 flippedScale = new Vector3(-1, 1, 1);

    private Rigidbody2D controllerRigibody;

    [Header("依赖脚本")] Animator animator;

    [Header("移动参数")]
    [SerializeField] float maxSpeed = 0.0f;
    [SerializeField] float maxGravityVelocity = 10.0f;
    [SerializeField] float jumpForce = 0.0f;
    [SerializeField] float groundedGravityScale = 0.0f;

    [SerializeField] float jumpGravityScale = 0.0f;
    [SerializeField] float fallGravityScale = 0.0f;

    private Vector2 vectorInput;
    private int jumpCount;
    private bool JumpInput;
    private float counter;

    private bool enableGravity;
    private bool canMove;

    private bool isOnGround;
    private bool isFacingLeft;
    private bool isJumping;
    private bool isFalling;

    private int animatorFirstLandingBool;
    private int animatorGroundedBool;
    private int animatorMovementSpeed;
    private int animatorVelocitySpeed;
    private int animatorJumpTrigger;
    private int animatorDoubleJumpTrigger;

    [Header("其它参数")]
    [SerializeField] private bool firstLanding;

    #endregion

    #region CallBackFunctions
    private void Awake()
    {
        controllerRigibody = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();
    }

    private void OnEnable()
    {
        InputManager.InputControl.GamePlayer.Movement.performed += ctx => vectorInput = ctx.ReadValue<Vector2>();
        InputManager.InputControl.GamePlayer.Jump.started += Jump_Started;
        InputManager.InputControl.GamePlayer.Jump.performed += Jump_Performed;
        InputManager.InputControl.GamePlayer.Jump.canceled += Jump_Canceled;
    }

    private void OnDisable()
    {
        InputManager.InputControl.GamePlayer.Movement.performed -= ctx => vectorInput = ctx.ReadValue<Vector2>();
        InputManager.InputControl.GamePlayer.Jump.started -= Jump_Started;
        InputManager.InputControl.GamePlayer.Jump.performed -= Jump_Performed;
        InputManager.InputControl.GamePlayer.Jump.canceled -= Jump_Canceled;
    }

    private void Start()
    {
        animatorFirstLandingBool = Animator.StringToHash("FirstLanding");
        animatorGroundedBool = Animator.StringToHash("Grounded");
        animatorVelocitySpeed = Animator.StringToHash("Velocity");
        animatorMovementSpeed = Animator.StringToHash("Movement");
        animatorJumpTrigger = Animator.StringToHash("Jump");
        animatorDoubleJumpTrigger = Animator.StringToHash("DoubleJump");

        animator.SetBool(animatorFirstLandingBool, firstLanding);

        enableGravity = true;
        canMove = true;
    }

    private void FixedUpdate()
    {
        UpdateVelocity();
        UpdateJump();
        UpdateDirection();
        UpdateGravityScale();
    }

    #endregion

    #region Movement

    private void UpdateVelocity()
    {
        Vector2 velocity = controllerRigibody.velocity;
        if (vectorInput.x != 0)
        {
            velocity.y = Mathf.Clamp(velocity.y, -maxGravityVelocity / 2, maxGravityVelocity / 2);
        }
        else
        {
            velocity.y = Mathf.Clamp(velocity.y, -maxGravityVelocity, maxGravityVelocity);
        }
        animator.SetFloat(animatorVelocitySpeed, controllerRigibody.velocity.y);
        if (canMove)
        {
            controllerRigibody.velocity = new Vector2(vectorInput.x * maxSpeed, velocity.y);
            animator.SetInteger(animatorMovementSpeed, (int)vectorInput.x);
        }
    }

    private void UpdateDirection()
    {
        //控制玩家的旋转
        if (controllerRigibody.velocity.x > 1f && isFacingLeft)
        {
            isFacingLeft = false;
            transform.localScale = flippedScale;
        }
        else if (controllerRigibody.velocity.x < -1f && !isFacingLeft)
        {
            isFacingLeft = true;
            transform.localScale = Vector3.one;
        }
    }

    private void UpdateJump()
    {
        if(isJumping && controllerRigibody.velocity.y < 0)
        {
            isFalling = true;
        }

        if (JumpInput)
        {
            controllerRigibody.AddForce(new Vector2(0,jumpForce), ForceMode2D.Impulse);
            isJumping = true;
        }
        if(isOnGround && !isJumping && jumpCount != 0) //如果已经落地了,则重置跳跃计数器
        {
            jumpCount = 0;
            counter = Time.time - counter;
        }
    }

    private void UpdateGravityScale()
    {
        var gravityScale = groundedGravityScale;

        if (!isOnGround)
        {
            
            gravityScale = controllerRigibody.velocity.y > 0.0f ? jumpGravityScale : fallGravityScale;
        }

        if (!enableGravity)
        {
            gravityScale = 0;
        }

        controllerRigibody.gravityScale = gravityScale;
    }

    private void JumpCancel()
    {
        JumpInput = false;
        isJumping = false;
        if(jumpCount == 1)
        {
            animator.ResetTrigger(animatorJumpTrigger);
        }
        else if(jumpCount == 2)
        {
            animator.ResetTrigger(animatorDoubleJumpTrigger);
        }
    }

    private void UpdateGrounding(Collision2D collision,bool exitState)
    {
        if (exitState)
        {
            if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian") || collision.gameObject.layer == LayerMask.NameToLayer("Soft Terrian"))
            {
                isOnGround = false;
            }
        }
        else
        {
            //判断为落地状态
            if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian")
                || collision.gameObject.layer == LayerMask.NameToLayer("Soft Terrian")
                && collision.contacts[0].normal == Vector2.up
                && !isOnGround)
            {
                isOnGround = true;
                isJumping = false;
                isFalling = false;
                //effect
            }
            //判断为头顶碰到物体状态
            else if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian") || collision.gameObject.layer == LayerMask.NameToLayer("Soft Terrian")
                && collision.contacts[0].normal == Vector2.down && isJumping)
            {
                JumpCancel();
            }
        }
        animator.SetBool(animatorGroundedBool, isOnGround);
    }

    public void StopHorizontalMovement()
    {
        Vector2 velocity = controllerRigibody.velocity;
        velocity.x = 0;
        controllerRigibody.velocity = velocity;
        animator.SetInteger(animatorMovementSpeed, 0);
    }

    public void SetIsOnGrounded(bool state)
    {
        isOnGround = state;
        animator.SetBool(animatorGroundedBool, isOnGround);
    }
    #endregion

    #region Combat
    private void Jump_Canceled(InputAction.CallbackContext context)
    {
        JumpCancel();
    }

    private void Jump_Performed(InputAction.CallbackContext context)
    {
        JumpCancel();
    }

    private void Jump_Started(InputAction.CallbackContext context)
    {

        counter = Time.time;
        if(jumpCount <= 1)
        {
            ++jumpCount;
            if(jumpCount == 1)
            {
                //Anim+Audio
                animator.SetTrigger(animatorJumpTrigger);
            }
            else if(jumpCount == 2)
            {
                //Anim+Audio+Effect
                animator.SetTrigger(animatorDoubleJumpTrigger);
            }
        }
        else
        {
            return;
        }
        JumpInput = true;
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        UpdateGrounding(collision, false);
    }

    private void OnCollisionStay2D(Collision2D collision)
    {
        UpdateGrounding(collision, false);
    }

    private void OnCollisionExit2D(Collision2D collision)
    {
        UpdateGrounding(collision, true);
    }
    #endregion

    #region Others

    public void FirstLanding()
    {

    }

    #endregion

}

 对于动画我们则要创建一个新的动画状态机名字就叫Jump StateMachine

为我们的Jump,Fall,Soft Land,Double Jump添加好动画

 

 

 

接着就是动画连线了。凡是到Jump和DoubleJump都只用Triiger来作为动画转化条件

 

 

 

 

 

 

 

 

 

 

 

 

回到Base状态机中,Walk,Run,Idle的动画到Jump状态机的动画暂时只有Jump和Fall,而且动画条件也都是一模一样的

 

 

 

 

 

 

 

 

 

 

 

 除此之外我们还要为动画添加行为脚本,

由此我们先对部分创建好行为脚本。 

 这些里面大多都是添加音乐和粒子效果所以先不用管,但FallingBehavior则要进行修改

using UnityEngine;

public class FallingBehavior : StateMachineBehaviour
{
    float lastPositionY;
    float fallDistance;
    CharacterController2D character;

    private void Awake()
    {
        //audio
        character = FindObjectOfType<CharacterController2D>();
    }

    // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        fallDistance = 0;
        animator.SetFloat("FallDistance", fallDistance);

        //auido
    }

    // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
    override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        if(lastPositionY > character.transform.position.y)
        {
            fallDistance += lastPositionY - character.transform.position.y;
        }
        lastPositionY = character.transform.position.y;
        animator.SetFloat("FallDistance", fallDistance);
    }

    // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        //audio
    }

    public void ResetAllParams()
    {
        lastPositionY = character.transform.position.y;
        fallDistance = 0;
    }
}

 


学习产出:

  参数先随便设计,设计好后效果如图。

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Unity从零开始制作空洞骑士】①制作人物的移动跳跃转向以及初始的动画制作 的相关文章

随机推荐

  • Python中的矩阵操作

    Numpy 通过观察Python的自有数据类型 我们可以发现Python原生并不提供多维数组的操作 那么为了处理矩阵 就需要使用第三方提供的相关的包 NumPy 是一个非常优秀的提供矩阵操作的包 NumPy的主要目标 就是提供多维数组 从而
  • html页面跳转的方法

    html页面跳转的方法 1 html中使用meta中跳转 通过meta可以设置跳转时间和页面 2 a标签直接跳转 a href http baidu com 百度一下 a 3 通过javascript中实现跳转 直接跳转window loc
  • python之微信公众号内容爬取一(亲测可用)

    import requests from lxml import etree headers User Agent Mozilla 5 0 Windows NT 10 0 Win64 x64 AppleWebKit 537 36 KHTML
  • 微信小程序实现数值监听(页面和组件属性)

    简介 目前文章主要介绍对页面属性值的监听以及组件属性值的监听 需要异页面监听数据 请跳转至另一个文章介绍 为什么需要监听属性值 当需要通过一个属性变化时候 需要计算相应的方法等 pc网站经常需要监听属性 那么小程序应该怎么去实现 实现方法
  • elementui的表格排序的组件之问题---条件改变样式消失

    这两天写了一个需求 就是当我改变时间的时候 排序功能消失 这我就想不是很简单吗 但是是我太单纯了 这个是一个后台 肯定会用到element的组件 然后果不其然用的就是element里面的表格排序组件 elementUI table 首先熟悉
  • 移动端适配方案

    总共的方法 1 通过媒体查询的方式 2 以天猫首页为代表的 flex 弹性布局 3 以淘宝首页为代表的 rem viewport缩放 4 rem 方式 1 基本知识点 物理像素 硬件上屏幕上横向和纵向有多少个像素点 逻辑像素dp 程序认为屏
  • KVM详解-WEB管理界面及安装win2016

    文章目录 KVM的简介 KVM简介 2 关于virtual machine manager的介绍 二 安装及环境的部署 1 安装时系统要求 3 安装KVM虚拟化软件 kvm部署 kvm安装 启动服务 验证安装结果 测试并验证安装结果 查看网
  • 【华为OD统一考试A卷

    华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一修改为OD统一考试 A卷 和OD统一考试 B卷 你收到的链接上面会标注A卷还是B卷 请注意 根据反馈 目前大部分收到的都是
  • 手机大厂必备测试技能-CTS 兼容测试

    01 何为CTS 相信小伙伴们都有用过各种款式的Android手机 如小米 魅族 华为 oppo vivo 虽然他们的页面长的都不太一样 比如小米的长这样 魅族的 oppo的 还有垂死挣扎的锤子 但是这些手机其实都是搭载的Android系统
  • linux运维笔记-初级部分内容

    本文出自 老男孩linux运维 博客 请务必保留此出处http oldboy blog 51cto com 2561410 476884 运维初级内容参考列表 一 学习方法篇 老男孩Linux实战运维笔记 学习方法系列 1 学好运维四要素
  • 微信小程序订阅消息

    HTTPS 调用 请求地址 POST https api weixin qq com cgi bin message subscribe send access token ACCESS TOKEN 消息订阅官方文档 https devel
  • Java获取当前时间的年月日时分秒方法

    相关内容 package com ob import java text ParseException import java text SimpleDateFormat import java util Calendar import j
  • 异地多活paxos实现:Multi-Master-Paxos-3

    Background 200行代码实现paxos kv 中介绍了一款非常简洁的分布式kv存储实现 它是基于 classic paxos 实现分布式一致性 在 paxos的直观解释 中我们提到 每次写入 也就是每个 paxos 实例需要2轮
  • .net 中间件的使用 Use,Run,Map,MapWhen,UseWhen

    net 中间件的使用 Use Run Map MapWhen UseWhen net 提供了几种添加自定义中间件的方法Use Run Map MapWhen UseWhen Use app Use async context next gt
  • 20210208-mmdetection模型转为tensorrt(trt)

    1 下载下载对应的的cuda 由于本机装的是10 1 所以下了个cuda 10 0 130 410 48 linux run 2 下载配置tensorrt 我下的是 TensorRT 7 0 0 11 配置如下 export TR PATH
  • 光纤通道速率查看_光纤好坏如何区分,OM1234多模光纤有何区别?

    1 OM1 颜色为橙色 核心尺寸 62 5um 数据速率 1GB 850nm 距离 高达300米 应用 短程网络 局域网 LAN 和专用网络 2 OM2 颜色为橙色 核心尺寸 50um 数据速率 1GB 850nm 距离 高达600米 通常
  • Linux中用root用户打开vscode

    先打开终端切换到root用户 su root 接着输入 sudo code user data dir vscode root
  • 对数器

    对数器的作用 对数器可以说是验证算法是否正确的一种方式 尤其是在笔试的时候 用贪心算法写出的程序 暂时无法用数学公式严格推导证明 只能通过大量的数据集验证算法的正确性 而大量的数据集当中要包括各种情况 各个方面都要考虑到 对我们自己来说 有
  • WDK_学习笔记_区块链+ViT和Swin transformer

    文章目录 摘要 一 項目 Hyperledger fabric技术的深入学习 1 1 安装 2 2 0 只记录问题 其余按文档操作即可 二 深度学习 Version Transformer ViT 和Swin Transformer 2 1
  • 【Unity从零开始制作空洞骑士】①制作人物的移动跳跃转向以及初始的动画制作

    事情的起因 首先我之前在b站的时候突然发现有个大佬说复刻了空洞骑士 点进去一看发现很多场景都福源道非常详细 当时我除了觉得大佬很强的同时也想自己试一下 而且当时对玩家血条设计等都很模糊 就想着问up主 结果因为制作的时间过了很久了 大佬也有