当前位置: 首页 > news >正文

Unity教程(十五)敌人战斗状态的实现

Unity开发2D类银河恶魔城游戏学习笔记

Unity教程(零)Unity和VS的使用相关内容
Unity教程(一)开始学习状态机
Unity教程(二)角色移动的实现
Unity教程(三)角色跳跃的实现
Unity教程(四)碰撞检测
Unity教程(五)角色冲刺的实现
Unity教程(六)角色滑墙的实现
Unity教程(七)角色蹬墙跳的实现
Unity教程(八)角色攻击的基本实现
Unity教程(九)角色攻击的改进

Unity教程(十)Tile Palette搭建平台关卡
Unity教程(十一)相机
Unity教程(十二)视差背景

Unity教程(十三)敌人状态机
Unity教程(十四)敌人空闲和移动的实现
Unity教程(十五)敌人战斗状态的实现


如果你更习惯用知乎
Unity开发2D类银河恶魔城游戏学习笔记目录


文章目录

  • Unity开发2D类银河恶魔城游戏学习笔记
  • 前言
  • 一、概述
  • 二、实现Player的检测
  • 三、创建接地状态
  • 三、实现战斗状态
    • (1)创建战斗状态
    • (2)状态切换
  • 总结 完整代码
    • Enemy.cs
    • SkeletonGroundedState.cs
    • SkeletonIdleState.cs
    • SkeletonMoveState.cs
    • SkeletonBattleState.cs
    • Enemy_Skeleton.cs


前言

本文为Udemy课程The Ultimate Guide to Creating an RPG Game in Unity学习笔记,如有错误,欢迎指正。

本节实现敌人的战斗状态。
对应b站视频:
【Unity教程】从0编程制作类银河恶魔城游戏P50

一、概述

本节中我们实现骷髅的战斗状态。
骷髅小怪在检测到玩家时,会向着玩家移动。在移动到一定距离时停止移动进入攻击状态。
由于我们想让骷髅在空闲和移动时均能转入战斗状态,我们创建超级状态接地状态,直接写接地状态到战斗状态的切换即可。
状态切换条件如下:
在这里插入图片描述

在这里插入图片描述

二、实现Player的检测

玩家的检测在Enemy基类中实现。
碰撞检测的详细讲解见Unity教程(四)碰撞检测

这里我们不再仅仅使用bool类型作为函数的返回值,而是使用RaycastHit2D返回更详细的信息。
RaycastHit2DUnity官方手册
Raycast包含的变量如下表:

变量介绍
centroid用于执行投射的图元的质心
collider射线命中的碰撞体
distance从射线原点到撞击点的距离
fraction射线上发生命中的距离的分数
normal射线命中的表面的法线矢量
point世界空间中射线命中碰撞体表面的点
rigidbody附加到命中的对象的 Rigidbody2D
transform命中的对象的变换

我们要新建一个过滤器WhatIsPlayer进行检测。
这里我们以骷髅的位置为起点,向它面向的方向发射射线检测,检测的最大距离设置为50.

为了方便调试我们还要绘制出攻击检测的线条,在Enemy里对实体中的OnDrawGizmos()函数进行重写。
攻击检测的线条绘制:起点为Enemy_Skeleton的位置,向右attackDistance找到终点。
在Enemy中添加如下代码:

    [SerializeField] protected LayerMask WhatIsPlayer;[Header("Attack Info")]public float attackDistance;public virtual RaycastHit2D IsPlayerDetected()=>Physics2D.Raycast(transform.position, Vector2.right * facingDir, 50 ,WhatIsPlayer);protected override void OnDrawGizmos(){base.OnDrawGizmos();Gizmos.color = Color.yellow;Gizmos.DrawLine(transform.position, new Vector3(transform.position.x + attackDistance * facingDir, transform.position.y));}

将Enemy_Skeleton的大小调大一点
在这里插入图片描述

在这里插入图片描述

创建一个新的WallCheck,并拖到Enemy_Skeleton中
在这里插入图片描述
在这里插入图片描述
将Wallcheck往下拖一些,以免与攻击检测重合。
在Enemy中重写OnDrawGizmos(),换一个颜色绘制出攻击检测。
给attackDistancce赋一个恰当的值。
在这里插入图片描述
在这里插入图片描述

将Enemy_Skeleton中WhatIsPlayer改为Player
在这里插入图片描述
新建Player和Enemy层。
在这里插入图片描述
在这里插入图片描述
Player改为Player层,Enemy_Skeleton改为Enemy层,修改时选择将它们所有子物体也改为对应层次。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、创建接地状态

创建接地状态SkeletonGroundedState,它继承自EnemyState。
在子菜单中创建构造函数,生成重写。
添加Enemy_Skeleton enermy,传递骷髅小怪独有的变量和函数,并修改构造函数。

//SkeletonGroundedState:骷髅接地状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkeletonGroundedState : EnemyState
{protected Enemy_Skeleton enemy;public SkeletonGroundedState(EnemyStateMachine _stateMachine, Enemy _enemyBase, Enemy_Skeleton _enemy,string _animBoolName) : base(_stateMachine, _enemyBase, _animBoolName){enemy=_enemy;}public override void Enter(){base.Enter();}public override void Exit(){base.Exit();}public override void Update(){base.Update();}
}

将SkeletonIdleState和SkeletonMoveState的父类改为SkeletonGroundedState,这时两个子类构造函数参数与父类相同,可以删除原有构造函数和Enemy_Skeleton enemy,直接在子菜单重新生成一个构造函数了。
在这里插入图片描述

三、实现战斗状态

(1)创建战斗状态

创建战斗状态SkeletonBattleState,它继承自EnemyState。
在子菜单中创建构造函数,生成重写。添加Enemy_Skeleton enermy,并修改构造函数。

    private Enemy_Skeleton enemy;public SkeletonBattleState(EnemyStateMachine _stateMachine, Enemy _enemyBase, Enemy_Skeleton _enemy, string _animBoolName) : base(_stateMachine, _enemyBase, _animBoolName){enemy=_enemy;}

在EnemySkeleton类中创建battleState。这里条件变量仍然选择“Move”,因为战斗状态仍然播放移动动画。

 #region 状态public SkeletonIdleState idleState { get; private set; }public SkeletonMoveState moveState { get; private set; }public SkeletonBattleState battleState { get; private set; }#endregionprotected override void Awake(){base.Awake();idleState = new SkeletonIdleState(stateMachine,this,this,"Idle");moveState = new SkeletonMoveState(stateMachine, this,this, "Move");battleState = new SkeletonBattleState(stateMachine, this, this, "Move");}

(2)状态切换

当检测到玩家时,骷髅由接地状态转换为战斗状态。
在SkeletonGroundedState的Update()函数中添加

    public override void Update(){base.Update();if(enemy.IsPlayerDetected())stateMachine.ChangeState(enemy.battleState);}

骷髅进入战斗状态时,要随玩家位置的变化改变移动方向。因此我们引入player的位置这个变量,通过它与骷髅位置的对比确定战斗状态骷髅移动的方向。

player.position.x > enemy.transform.position.x,玩家在骷髅右边,移动方向向右
player.position.x < enemy.transform.position.x,玩家在骷髅左边,移动方向向左

//SkeletonBattleState:骷髅战斗状态
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkeletonBattleState : EnemyState
{private Transform player;private Enemy_Skeleton enemy;private int moveDir;public SkeletonBattleState(EnemyStateMachine _stateMachine, Enemy _enemyBase, Enemy_Skeleton _enemy, string _animBoolName) : base(_stateMachine, _enemyBase, _animBoolName){enemy=_enemy;}public override void Enter(){base.Enter();player = GameObject.Find("Player").transform;}public override void Exit(){base.Exit();}public override void Update(){base.Update();if(player.position.x > enemy.transform.position.x)moveDir = 1;else if(player.position.x < enemy.transform.position.x)moveDir = -1;enemy.SetVelocity(enemy.moveSpeed * moveDir, enemy.rb.velocity.y);}
}

效果如下:
在这里插入图片描述

而当玩家进入骷髅的攻击距离时,骷髅停止移动切换为攻击状态。根据上述内容所讲,骷髅与玩家的距离可由RaycastHit2D里的distance获得。攻击状态我们先控制输出代替,具体攻击状态内容我们下一节再进行实现。
Update中添加如下代码:

    public override void Update(){base.Update();if (enemy.IsPlayerDetected()){if (enemy.IsPlayerDetected().distance < enemy.attackDistance){Debug.Log("attack");enemy.ZeroVelocity();return;}}if(player.position.x > enemy.transform.position.x)moveDir = 1;else if(player.position.x < enemy.transform.position.x)moveDir = -1;enemy.SetVelocity(enemy.moveSpeed * moveDir, enemy.rb.velocity.y);}

在这里插入图片描述

总结 完整代码

Enemy.cs

添加碰撞检测和攻击距离变量,实现攻击检测的函数和攻击检测的绘制

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Enemy : Entity
{[SerializeField] protected LayerMask WhatIsPlayer;[Header("Move Info")]public float moveSpeed = 1.5f;public float idleTime = 2.0f;[Header("Attack Info")]public float attackDistance;public EnemyStateMachine stateMachine;protected override void Awake(){base.Awake();stateMachine = new EnemyStateMachine();}protected override void Update(){base.Update();stateMachine.currentState.Update();}public virtual RaycastHit2D IsPlayerDetected()=>Physics2D.Raycast(transform.position, Vector2.right * facingDir, 50 ,WhatIsPlayer);protected override void OnDrawGizmos(){base.OnDrawGizmos();Gizmos.color = Color.yellow;Gizmos.DrawLine(transform.position, new Vector3(transform.position.x + attackDistance * facingDir, transform.position.y));}
}

SkeletonGroundedState.cs

创建接地状态,由移动和空闲状态继承。实现切换到战斗状态。

//SkeletonGroundedState:骷髅接地状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkeletonGroundedState : EnemyState
{protected Enemy_Skeleton enemy;public SkeletonGroundedState(EnemyStateMachine _stateMachine, Enemy _enemyBase, Enemy_Skeleton _enemy,string _animBoolName) : base(_stateMachine, _enemyBase, _animBoolName){enemy=_enemy;}public override void Enter(){base.Enter();}public override void Exit(){base.Exit();}public override void Update(){base.Update();if (enemy.IsPlayerDetected())stateMachine.ChangeState(enemy.battleState);}
}

SkeletonIdleState.cs

修改构造函数

//SkeletonIdleState:骷髅空闲状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkeletonIdleState : SkeletonGroundedState
{public SkeletonIdleState(EnemyStateMachine _stateMachine, Enemy _enemyBase, Enemy_Skeleton enemy, string _animBoolName) : base(_stateMachine, _enemyBase, enemy, _animBoolName){}public override void Enter(){base.Enter();stateTimer = enemy.idleTime;}public override void Exit(){base.Exit();}public override void Update(){base.Update();if (stateTimer < 0)stateMachine.ChangeState(enemy.moveState);}
}

SkeletonMoveState.cs

//SkeletonMoveState:骷髅移动状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkeletonMoveState : SkeletonGroundedState
{public SkeletonMoveState(EnemyStateMachine _stateMachine, Enemy _enemyBase, Enemy_Skeleton enemy, string _animBoolName) : base(_stateMachine, _enemyBase, enemy, _animBoolName){}public override void Enter(){base.Enter();}public override void Exit(){base.Exit();}public override void Update(){base.Update();enemy.SetVelocity(enemy.moveSpeed*enemy.facingDir,enemy.rb.velocity.y);if(!enemy.isGroundDetected() || enemy.isWallDetected()){enemy.Flip();stateMachine.ChangeState(enemy.idleState);}}
}

SkeletonBattleState.cs

创建战斗状态,实现切换到攻击状态,和随玩家移动改变方向。

//SkeletonBattleState:骷髅战斗状态
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkeletonBattleState : EnemyState
{private Transform player;private Enemy_Skeleton enemy;private int moveDir;public SkeletonBattleState(EnemyStateMachine _stateMachine, Enemy _enemyBase, Enemy_Skeleton _enemy, string _animBoolName) : base(_stateMachine, _enemyBase, _animBoolName){enemy=_enemy;}public override void Enter(){base.Enter();player = GameObject.Find("Player").transform;}public override void Exit(){base.Exit();}public override void Update(){base.Update();if (enemy.IsPlayerDetected()){if (enemy.IsPlayerDetected().distance < enemy.attackDistance){Debug.Log("attack");enemy.ZeroVelocity();return;}}if(player.position.x > enemy.transform.position.x)moveDir = 1;else if(player.position.x < enemy.transform.position.x)moveDir = -1;enemy.SetVelocity(enemy.moveSpeed * moveDir, enemy.rb.velocity.y);}
}

Enemy_Skeleton.cs

创建战斗状态

//Enemy_Skeleton:骷髅敌人
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Enemy_Skeleton : Enemy
{#region 状态public SkeletonIdleState idleState { get; private set; }public SkeletonMoveState moveState { get; private set; }public SkeletonBattleState battleState { get; private set; }#endregionprotected override void Awake(){base.Awake();idleState = new SkeletonIdleState(stateMachine,this,this,"Idle");moveState = new SkeletonMoveState(stateMachine, this,this, "Move");battleState = new SkeletonBattleState(stateMachine, this, this, "Move");}protected override void Start(){base.Start();stateMachine.Initialize(idleState);}protected override void Update(){base.Update();}}

相关文章:

Unity教程(十五)敌人战斗状态的实现

Unity开发2D类银河恶魔城游戏学习笔记 Unity教程&#xff08;零&#xff09;Unity和VS的使用相关内容 Unity教程&#xff08;一&#xff09;开始学习状态机 Unity教程&#xff08;二&#xff09;角色移动的实现 Unity教程&#xff08;三&#xff09;角色跳跃的实现 Unity教程&…...

利用深度学习实现验证码识别-3-ResNet18

在当今数字化时代&#xff0c;验证码作为一种重要的安全验证手段&#xff0c;广泛应用于各种网络场景。然而&#xff0c;传统的验证码识别方法往往效率低下&#xff0c;准确率不高。今天&#xff0c;我们将介绍一种基于 ResNet18 的验证码识别方法&#xff0c;它能够高效、准确…...

UDP通信实现

目录 前言 一、基础知识 1、跨主机传输 1、字节序 2、主机字节序和网络字节序 3、IP转换 2、套接字 3、什么是UDP通信 二、如何实现UDP通信 1、socket():创建套接字 2、bind():绑定套接字 3、sendto():发送指定套接字文件数据 4、recvfrom():接收指定地址信息的数据 三…...

windows下使用vscode编写运行以及调试C/C++

vscode支持类似于vs的断点调试c/c&#xff0c;也可以直接编译&运行c/c 先是编译运行 c/c的方法 微软官方起初设定的科学做法(这也是现在的科学做法)是通过在vscode集成控制台写命令行的方式来实现编译运行程序的,但也可以通过code runner插件…...

python容器4--集合

&#xff08;1&#xff09; 什么是集合 集合&#xff1a;Python中使用关键字set表示 集合中存储多个、没有顺序的、不能重复的、可以是不同类型的多个数据&#xff01; &#xff08;2&#xff09; 集合的声明 python中通过set()或者花括号声明空集合、非空集合 # 声明空集…...

MySQL record 01 part

更改密码&#xff1a; alter user rootlocalhost identified with mysql_native_password by ‘123456’; 注意&#xff1a; 在命令行方式下&#xff0c;每条MySQL的命令都是以分号结尾的&#xff0c;如果不加分号&#xff0c;MySQL会继续等待用户输入命令&#xff0c;直到MyS…...

2024年高教社杯全国大学生数学建模竞赛A题思路(2024数学建模国赛A题思路)

A题 “板凳龙” 闹元宵 “板凳龙”,又称“盘龙”,是浙闽地区的传统地方民俗文化活动。人们将少则几十条,多则上百条的板凳首尾相连,形成蜿蜒曲折的板凳龙。盘龙时,龙头在前领头,龙身和龙尾相随盘旋,整体呈圆盘状。一般来说,在舞龙队能够自如地盘入和盘出的前提下,盘龙…...

Go语言基础语法 20240904更新

代码开源地址 https://github.com/zhangdapeng520/zdpgo_basic 快速入门 示例代码&#xff1a; package mainimport "fmt"func main() {fmt.Println("Hello World") }第一行代码 package 用来声明包名。main包时整个程序的入口包&#xff0c;在一个Go语…...

软件测试 | 性能测试

性能测试的概念 为了 发现系统性能问题 或 获取系统性能相关指标 而进行的测试。 常见性能测试指标 并发数 即并发用户数。 从业务层面看&#xff0c;并发用户数指的是 实际使用系统的用户总数。从后端服务器层面看&#xff0c;指的是 web服务器在一段时间内处理浏览器请求而建…...

Arduino IDE

Arduino IDE&#xff08;集成开发环境&#xff09;的安装过程是一个相对直观且易于操作的流程&#xff0c;主要步骤包括下载、安装和配置。以下将详细阐述Arduino IDE的安装过程&#xff0c;同时提供一些背景信息和注意事项&#xff0c;确保安装过程顺利进行。 一、Arduino ID…...

统计学习方法与实战——统计学习方法之感知机

感知机 感知机三要素分析模型策略损失函数选择 算法原始形式对偶形式 相关问题 例子iris数据集分类实战数据集查看 显示结果sklearn 实战感知机 习题解答习题2.1解题步骤反证法 习题2.2习题2.3凸壳线性可分线性可分证明凸壳不相交证明充分性&#xff1a;凸壳不相交\Rightarrow⇒…...

语言学习有捷径?没错!这4个方法让你轻松搞定英语翻译

现在全世界都在用英语&#xff0c;这门语言真的超级重要。不管你是学习、上班还是出去玩&#xff0c;会点英语翻译肯定能帮上大忙。但是&#xff0c;对很多人来说&#xff0c;翻译英语还是挺难的。别急&#xff0c;今天我就来给你介绍几个超好用的英语翻译工具&#xff0c;让你…...

聊一聊大型网站稳定性建设思路

目录 架构阶段的稳定性建设项目 编码阶段的稳定性建设 测试阶段的稳定性建设 发布阶段的稳定性建设 运行阶段的稳定性建设项目 故障发生时的稳定性建设 网站稳定性的建设是一项综合的系统工程&#xff0c;就像人的健康一样&#xff0c;如果平时不注意健康饮食、不注意锻炼…...

Nginx常用配置

Windows版本Nginx开机自启动 可直接下载已经配置好的文件&#xff0c;点击即可下载&#xff1a;Windows版本Nginx1.26.0 下载WinSW v2.12.0 首先从https://github.com/winsw/winsw/releases下载WinSW v2.12.0 下载Nginx 下载地址https://nginx.org/en/download.html 修…...

前端开发中遇到的小问题以及解决方案记录2

1、H5中适配屏幕的工具-postcss-px-to-viewport postcss-px-to-viewport。因为设计稿一般给的都是375px宽度的&#xff0c;所以假如一个字体是16px&#xff0c;那么在开发中不能直接写死为16px&#xff0c;因为各个厂商的手机屏幕大小是不同的&#xff0c;所以要根据屏幕大小去…...

Qt-常用控件(3)-输入类

1. QLineEdit QLineEdit 用来表示单行输入框.可以输入一段文本,但是不能换行 核心属性 属性说明text输入框中的文本inputMask输入内容格式约束maxLength最大长度frame是否添加边框echoMode显示方式. QLineEdit::Normal :这是默认值&#xff0c;文本框会显示输入的文本。QLineE…...

使用Docker启动Redis容器并映射端口

在现代软件开发中&#xff0c;Redis 是一种非常流行的开源内存数据结构存储&#xff0c;通常用作数据库、缓存或消息传递系统。Docker 是一个开源的应用容器引擎&#xff0c;它允许开发者打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux …...

用fastapi搭建cpca地址提取服务接口

以前的客户地址比较乱&#xff0c;现在想提取出省份城市&#xff0c; 开始了解分词技术&#xff0c;后发现python有这样的库 cpca提取地址挺不错&#xff0c;可以从垃圾地址中提取省市区以及区号。 文章会用fastapi搭建服务端 通过post调用cpca&#xff0c;提取来了后&#…...

libvncclient编写多线程qt的VNC客户端

概述 使用qt和libvncclient编写vnc的客户端程序&#xff0c;多线程读写&#xff0c;拒绝卡顿。qt环境&#xff1a;5.15.3libvncclient&#xff1a;0.9.14下载地址&#xff1a;https://github.com/LibVNC/libvncserver/releases 编译libvncclient 打开CMakeList文件&#xff…...

视频处理基础之gradio框架实现

这些函数是用于处理视频文件的Python代码片段&#xff0c;它们依赖于ffmpeg和ffprobe工具&#xff0c;这些工具是FFmpeg项目的一部分&#xff0c;用于处理视频和音频数据。下面是每个函数的用途和用法的总结&#xff1a; 1. ffmpeg_installed() 函数&#xff1a; - 用途&am…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...

6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础

第三周 Day 3 &#x1f3af; 今日目标 理解类&#xff08;class&#xff09;和对象&#xff08;object&#xff09;的关系学会定义类的属性、方法和构造函数&#xff08;init&#xff09;掌握对象的创建与使用初识封装、继承和多态的基本概念&#xff08;预告&#xff09; &a…...

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...

向量几何的二元性:叉乘模长与内积投影的深层联系

在数学与物理的空间世界中&#xff0c;向量运算构成了理解几何结构的基石。叉乘&#xff08;外积&#xff09;与点积&#xff08;内积&#xff09;作为向量代数的两大支柱&#xff0c;表面上呈现出截然不同的几何意义与代数形式&#xff0c;却在深层次上揭示了向量间相互作用的…...

在Zenodo下载文件 用到googlecolab googledrive

方法&#xff1a;Figshare/Zenodo上的数据/文件下载不下来&#xff1f;尝试利用Google Colab &#xff1a;https://zhuanlan.zhihu.com/p/1898503078782674027 参考&#xff1a; 通过Colab&谷歌云下载Figshare数据&#xff0c;超级实用&#xff01;&#xff01;&#xff0…...

C++ 类基础:封装、继承、多态与多线程模板实现

前言 C 是一门强大的面向对象编程语言&#xff0c;而类&#xff08;Class&#xff09;作为其核心特性之一&#xff0c;是理解和使用 C 的关键。本文将深入探讨 C 类的基本特性&#xff0c;包括封装、继承和多态&#xff0c;同时讨论类中的权限控制&#xff0c;并展示如何使用类…...