“摄像机”跟随及攻击抖动实现

学习Unity的摄像机功能,可以帮助我们实现摄像机对人物的跟随移动,还可以使用这个工具自带的插件,摄像机震动,颤动,增强打击感;

首先来安装一下这个插件,window菜单--packageManage--左上角Unity Registry--右上角搜索插件Cinemachine,install安装

在Hierarchy窗口直接来添加摄像机

左上角“ + ”--Cinemachine--2D Cinema,保留原来的命名

然后会发现当前Game窗口,人物和场景都不见了

因为Virtual Camera并没有选择跟随谁,或者正在观看谁

我们把Player拖拽进来,Look At,Follow

现在就可以成功看到Player,把摄像机放在列表上方;

有了这个摄像机,默认情况下就可以实现人物跟随,运行游戏查看效果

我们还可以调整一下详细的设置,在Body的下拉菜单当中

可以调整跟随的中心点位置,人物是脚底为中心点,可以调整一下y轴,保证跟随人物中心点位置

 Dead Zone Width,Dead Zone Height,通过调整这个高度和宽度可以给摄像机有一定的缓冲值;所以如果人物没有移动超过这个范围以上,他是不会进行摄像机的跟随的

点击空白位置,然后运行游戏

稍微调整位移,小范围的位移,摄像机不会进行跟随,一旦超出范围,摄像机才做一个跟随(里面有非常多的选项,可以进行自主调整)

接下来解决摄像机跟随我们到什么程度

切换到Scene的场景当中,我们先把这个场景画的大一些

我们希望限制一下我的摄像机跟随的范围,不希望摄像机穿帮透露出我们的画面下边和上边没有绘制的区域,所以我们要给他添加一个边界的限制

我们留意在virtal Camera选择的情况下,inspector窗口下方,有Extensions可以给他添加扩展内容,这个扩展内容当中有非常多的东西,点击下拉菜单,有很多的选项,

首先我们要添加一个非常重要的东西Cinemachine Pixel Perfect(帮助我们在我们的像素旋转或产生畸变的时候,不会出现像素扭曲,保持我们的单位像素

另外我们还要添加一个工具Cinemachine Confiner2D(帮助我们限定一定的区域来控制摄像机的移动范围)

在Bounding Shape 2D中要添加一个Collider2D类型的变量,而这个变量可以通过我们整个场景当中的大型的collider绘制来限制相机的可移动的范围,所以接下来我们来实现一下摄像机的限制范围

在Hierarchy窗口创建一个新的game object(Creat Empty),命名为Bounds边界范围;

为Bounds添加一个Polygon Collider 2D的组件

勾选Is Trigger(不然的话,就会把我们的人物以及其他所有的碰撞体相关的内容都会被弹开)

设置一下边界位置,可以设置任意的形状,然后摄像机将只在这个形状范围之内产生跟随的移动

先随便设置一个样子,绿色的线框

 我们点击Virtual Camera,将Bounds拖拽进来给到我们的Boounding Shape 2D

点击运行测试,接下来我们就可以看到摄像机只能在我们绘制的区域内移动了,摄像机有了一定的区域边框的限制

这样我们就实现了场景当中摄像机的边界,可以自己修改一下,将边界调整一下

调整规整边界,我们可以删除它多余的points,一半用四个点做一个矩形就可以了,可以通过实际的设置数值来调整点的位置

这样我们就绘制好边框了,可以运行测试一下

可以看到整个摄像机只能在绿色的范围内进行移动

这样我们就成功实现了边框的内容

以后我们还会有多个场景,从一个场景转换到另外一个场景,我们如何获得当前场景的这个摄像机的边框位置,我们要在代码当中来进行实现

我们通过代码的方式,每次切换场景,要获得一下这个摄像机的边界,所有我们为了方便查找,先为这个边界添加一个标签

选择Bounds,Tag--Add Tag 起名为Bounds

重新选择这个物体,为他选择这个标签

我们希望我的Virtual Camera可以获得我的Cinemachine Confined 2D这个组件,然后我们通过修改这个变量值,每次切换场景之后,都去找一下这个被标记了Bounds的这个物体,将他身上的Collider添加到Cinemachine Confined 2D的Bounding Shape 2D

接下来来创建代码

选择Script文件夹,选择Utillitiles下创建一个c#脚本,叫做CameraControl(摄像机控制脚本)

将这个代码挂载在virtual Camera上

打开代码

Cinemachine是一个插件,我们想要在代码当中调用Cinemachine的话,要先调用它的命名空间using Cinemachine

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

然后接下来我们要获得confined 2D的组件

在Awake当中Getcomponent

public class CameraControl : MonoBehaviour
{private CinemachineConfiner2D confiner2D;private void Awake(){confiner2D = GetComponent<CinemachineConfiner2D>();}
}

接下来我们就可以通过我们的代码获得我们的Shape 2D

创建一个函数方法GetNewCameraBounds,以后在做场景切换的时候,可以直接用这个函数的方法来调用,获得我们所有场景当中的Bounds

 private void GetNewCameraBounds(){}

创建一个临时变量obj在找到这个挂载了Bounds的物体,用GameObject的方法,在这里面unity帮我们内置了一个查找的方法,输入find,会提示给我们非常多的方法来使用,刚才我们标记了标签,所以在此处我们使用FindGameObjectWithTag

private void GetNewCameraBounds()
{var obj = GameObject.FindGameObjectWithTag("Bounds");
}

找到这个东西以后,我们要确定一下场景当中到底有没有;我们需要加上一个约束判断,如果OBJ为空,return不需要执行其他的内容,帮助我们停止代码;如果不为空,我们才执行下边的内容。

我们既然获得了物体,我们就可以获得他身上Collider2D的组件,然后给到我们的Confiner2D;Confiner2D的BoundingShape2D=obj上get的Confiner2D类型

Collider2D是一个基类,所有的Box Collider都基于我们的Collider2D,所以我们用Collider2D就可以代表所有类型的碰撞体了

 private void GetNewCameraBounds(){var obj = GameObject.FindGameObjectWithTag("Bounds");if (obj == null)return;confiner2D.m_BoundingShape2D = obj.GetComponent<Collider2D>();}

保持代码返回unity

我们看一下我们Virtual Camera--Cinemachine Confiner,在我们获得了我们的碰撞体之后,下面有个按钮叫做Invalidate Cache(强制我们清理一下缓存,下边有详细的说明,如果一旦从一个场景切换到另一个场景,从一个边界切换到另一个边界,需要通过这个默认的函数方法,来清理掉之前的形状缓存,这样才能让他应用于新的这个形状),所以我们可以直接调用这个函数Invalidate Cache,我们在代码当中把它添加进去

打开CameraControl代码,

获得一个新的图形之后,要调用Invalidate Cache

这样我们就成功的在游戏一开始,获得的标签身上找到Collider给到我们的赋值,然后清一下缓存

public class CameraControl : MonoBehaviour
{private CinemachineConfiner2D confiner2D;private void Awake(){confiner2D = GetComponent<CinemachineConfiner2D>();}private void GetNewCameraBounds(){var obj = GameObject.FindGameObjectWithTag("Bounds");if (obj == null)return;confiner2D.m_BoundingShape2D = obj.GetComponent<Collider2D>();confiner2D.InvalidateCache();}
}

那我们在说明时候来调用呢,在游戏的一开始,我们暂时先写在这儿调用这个函数方法得到新的摄像机范围

在场景切换之后,我们还要在里面做一些更改和修整;目前暂时在游戏开始时获得这个边界

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;public class CameraControl : MonoBehaviour
{private CinemachineConfiner2D confiner2D;private void Awake(){confiner2D = GetComponent<CinemachineConfiner2D>();}//TODO:场景切换后的更改private void Start(){GetNewCameraBounds();}private void GetNewCameraBounds(){var obj = GameObject.FindGameObjectWithTag("Bounds");if (obj == null)return;confiner2D.m_BoundingShape2D = obj.GetComponent<Collider2D>();confiner2D.InvalidateCache();}
}

保存代码,返回unity

我们来看一下,我们先将Virtual Camera的Collider删掉,让这个component没有获得任何变量,运行游戏,查看他能不能得到我们的Bounds,然后赋值给我们的Virtual Camera;

可以看到它自动就获得了这个边界,场景当中自动绘制好

这样我们就成功实现了获取当前场景标签Bounds的这个物体,用这个物体来控制我的摄像机的边界

接下来我们要来添加一个摄像机的震动反馈;每次攻击的时候,屏幕上都会有一些震动,这样会让我们的动作游戏更有打击感的效果

在VirtualCamera的Cinemachine当中来添加另外一个extension扩展的工具,点击下拉菜单,选择CinemachineImpulseListener监听摄像机的震动(impulse突然的冲击力“在添加Rigidbody刚体的时候使用过”)

也可以看一下这里面的说明,这个ImpulseListener他会根据我们发送的信号,来产生实际的摄像机的震动,所以它需要一个震动源,就是CinemachineImpulseSource;有了这个震动源,他才会监听每一次的震动事件

另外下边也有选项,默认情况下Unity都是3D,我们摄像机距离背景z轴为10,有10的距离;震动的方向也是3D的,当前我们的是2D游戏,所以只要有上下左右的震动就好了,所以勾选 Use 2D Distan,

我们有了震动的监听,接下来我们需要一个震动源

我们在Hierarchy窗口创建一个新的空的GameObject(Create Empty)命名为Camera Shake摄像机震动,调整窗口画面,我们把摄像机都放在上面

在这个上面我们来添加震动源

Add Component搜索Cinemachine Impulse Source,

这就是一个震动源,这个震动源里面帮助我们提供了很多预制的震动效果

它下面为我们提供了一个Test with Force,也就是我们可以模拟测试一下,不过他只有在运行的时候才可以测试,点Invoke测试

我们点击运行,来看一下这个摄像机的震动效果,根据效果来修改我们想要的数值

Impulse Shape:Bump(上下震动),下拉菜单还要其他的效果;当前这些震动是有固定的波幅的,可以打开下拉菜单,查看它的波幅的样子,希望x,y方向都有震动,我们可以在下面添加一下数值

如果我们希望震动不是那么强烈的话,可以将振幅稍微改小一点

注意,要在停止运行的时候重新修改数值,确定数值修改好了

类型我们选择Explosion爆炸类型

我们希望在每次攻击的时候,启动一下这个震动

接下来到代码当中来实现(通过代码来实现,在这个效果框中,有提示内容,如果想要调用这个组件,我们要使用的ApI的函数方法是GenerateImpulse),所以我们调用这个组件,然后使用这个函数方法GenerateImpulse,就会播放震动

我们要在Virtual Camera当中获得一下这个Cinemachine Impulse Source;

打开CameraControl代码,当中创建一个变量impulseSource来获得它

public class CameraControl : MonoBehaviour
{private CinemachineConfiner2D confiner2D;public CinemachineImpulseSource impulseSource;

保存返回unity

进行拖拽赋值

现在我们有了CameraShake之后,我们就可以直接用GenerateImpulse来执行震动了

当人物和敌人攻击或者受伤的时候才播放震动,

用事件监听的方式;接下来我们再创建一个ScriptableObject的事件方法,在ScriptableObject文件夹下创建,这次我们不用传递参数,起名为VoidEventSO(没有参数的事件)只要不传递任何变量参数的,我们都可以用同一个SO去创建实际上的Ass文件,来实现我们想要的事件

打开代码,进行编写

快速创建

using UnityEngine;[CreateAssetMenu(menuName ="Event/VoidEventSO")]
public class VoidEventSO:ScriptableObject
{}

保存代码,返回unity,确定我们可以成功创建

在Project的Events文件夹下,点击加号选择Event--VoidEventSO,创建,

起名为CameraShake Event

打开代码,继续编写

在上面添加调用命名空间

我们既然不传递任何的参数,我们就使用最基本的方法,在下面创建UnityAction

不需要传递任何参数

using UnityEngine;
using UnityEngine.Events;[CreateAssetMenu(menuName ="Event/VoidEventSO")]
public class VoidEventSO:ScriptableObject
{public UnityAction OnEventRaised;public void RaiseEvent(){OnEventRaised?.Invoke();}
}

保存返回unity

选择Player,在Player受伤的基础只是,我们班这个CameraShake这个事件拖拽进来

只要人物受伤,就呼叫一下,广播人物受伤,摄像机实现震动

所以我们每一个敌人在受到伤害或者死亡的时候,我们都要添加这个方法,

这样广播就已经都设置好了

接下来要实现监听,监听我们就要到Virtual Camera,在CameraControl当中去进行监听了

打开代码,因为我们已经获得了这个组件impulse;所以我们要监听一下这个事件

public class CameraControl : MonoBehaviour
{private CinemachineConfiner2D confiner2D;public CinemachineImpulseSource impulseSource;public VoidEventSO cameraShakeEvent;

然后添加一下注册的方法,取名为OnCameraShakeEvent

 private void OnEnable(){cameraShakeEvent.OnEventRaised += OnCameraShakeEvent;}private void OnDisable(){cameraShakeEvent.OnEventRaised -= OnCameraShakeEvent;}

然后让编译器帮助我们自动生成函数OnCameraShakeEvent,在这个函数中执行摄像机的震动

private void OnCameraShakeEvent()
{impulseSource.GenerateImpulse();
}

保存代码,返回unity,

先把事件拖拽到VirtualCamera

测试一下

这样我们就成功实现了摄像机的震动,受到攻击的摄像机反馈震动,整个游戏的打击感就有了很大的提升

在CameraShake当中我们也可以自己创建震动效果,波幅的大小也可以使用震动文件,来产生屏幕上实际的震动效果

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

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

相关文章

vcpkg 从清单文件安装依赖项

vcpkg 有两种运行模式&#xff1a;经典模式和清单模式。清单文件有自己的 vcpkg_installed 目录&#xff0c;可在其中安装依赖项&#xff0c;与所有包都安装在通用 %VCPKG_ROOT%/installed 目录中的经典模式不同。 因此&#xff0c;每个项目都可以有自己的清单和自己的一组依赖…

R语言机器学习算法实战系列(十)自适应提升分类算法 (Adaptive Boosting)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍原理步骤教程下载数据加载R包导入数据数据预处理数据描述数据切割调节参数构建模型预测测试数据评估模型模型准确性混淆矩阵模型评估指标ROC CurvePRC Curve特征的重要性保存模型总…

生发产品哪个效果最好?油秃头秋冬季养发搭子

如果你是大额头 或者 M型发际线&#xff0c;无论是天生的 亦或者是后天造成的&#xff0c;养发防脱一定要重视起来&#xff0c;因为防脱育发是需要循序渐进坚持的&#xff0c;今天就给大家分享一下几个特别有效的育发液&#xff0c;选对产品养发那真是稳了~ 1、露卡菲娅防脱育发…

Unity之XR Interaction Toolkit 射线拖拽3DUI

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、想实现的功能二、实现原理1.UI挂在XRGrabInteractable、刚体、BoxCollder2.修改刚体属性3.加BoxCollder 总结 前言 VR项目里正常情况有放置两种3DUI的方式…

Ovis: 多模态大语言模型的结构化嵌入对齐

论文题目&#xff1a;Ovis: Structural Embedding Alignment for Multimodal Large Language Model 论文地址&#xff1a;https://arxiv.org/pdf/2405.20797 github地址&#xff1a;https://github.com/AIDC-AI/Ovis/?tabreadme-ov-file 今天&#xff0c;我将分享一项重要的研…

关于使用 C# 处理水位数据多种格式的统一转换

关于使用 C# 处理水位数据多种格式的统一转换 1、前言2、水位数据的多种格式3、水位数据多种格式的统一转换程序展示4、水位数据多种格式的统一转换 C# 代码4.1、声明引用命名空间4.2、多种格式的统一转换 C# 代码4.3、多种格式的统一转换 C# 代码&#xff0c;文件输出保存 1、…

微知-Lecroy力科的PCIe协议分析仪型号命名规则(PCIe代,金手指lanes数量)

文章目录 要点主要型号命名规则各代主要产品图片Summit M616 协议分析仪/训练器Summit T516 分析仪Summit T416 分析仪Summit T3-16分析仪Summit T28 分析仪 综述 要点 LeCroy(力科)成立于1964年&#xff0c;是一家专业生产示波器厂家。在美国纽约。一直把重点放在研制改善生产…

Hallo2 长视频和高分辨率的音频驱动的肖像图像动画 (数字人技术)

HALLO2: LONG-DURATION AND HIGH-RESOLUTION AUDIO-DRIVEN PORTRAIT IMAGE ANIMATION 论文&#xff1a;https://arxiv.org/abs/2410.07718 代码&#xff1a;https://github.com/fudan-generative-vision/hallo2 模型&#xff1a;https://huggingface.co/fudan-generative-ai/h…

TikTok营销实用技巧与数据分析工具:视频洞察

TikTok凭借其独特的机制和庞大的流量&#xff0c;成为了众多品牌和卖家对产品进行宣传推广的必要平台之一。要在TikTok上优化营销效果、提升推广效率&#xff0c;可以使用平台提供的重要工具——视频洞察&#xff08;Video Insights&#xff09;。 一、视频洞察功能与技巧 视频…

线性回归(一)

线性回归 1.基本术语 ①特征&#xff1a;预测所依据的自变量称为特征或协变量 ②标签&#xff1a;试图预测的目标称为标签或目标 2.举个栗子 线性假设是指目标&#xff08;房屋价格&#xff09;可以表示为特征&#xff08;面积和房龄&#xff09;的加权和&#xff0c;如下面…

YOLOv11入门到入土使用教程(含结构图)

一、简介 YOLOv11是Ultralytics公司在之前的YOLO版本上推出的最新一代实时目标检测器&#xff0c;支持目标检测、追踪、实力分割、图像分类和姿态估计等任务。官方代码&#xff1a;ultralytics/ultralytics&#xff1a;ultralytics YOLO11 &#x1f680; (github.com)https://g…

解决跨域问题

跨域是浏览器受同源策略的限制&#xff0c;同源策略是浏览器为确保资源安全&#xff0c;而遵循的一种策略&#xff0c;该策略对访问资源进行了一些限制&#xff08;如发送 ajax 请求&#xff0c;操作 dom&#xff0c;读取 cookie&#xff09;。 最常见的影响就是发送 ajax 请求…

【微知】如何通过命令行在非串口界面触发sysrq的help信息?(echo h > /proc/sysrq-trigger)

背景 在服务器上&#xff0c;触发sysrq通常需要在串口执行sysrq热键&#xff0c;比如 ~相关的操作 如何通过在ssh界面触发sysrq触发一些操作&#xff1f; 命令 通过sysrq指定的/proc接口文件进行操作 echo h > /proc/sysrq-trigger dmesg #产看输出的帮助信息然后根据打…

Junit + Mockito保姆级集成测试实践

一、做好单测&#xff0c;慢即是快 对于单元测试的看法&#xff0c;业界同仁理解多有不同&#xff0c;尤其是在业务变化快速的互联网行业&#xff0c;通常的问题主要有&#xff0c;必须要做吗&#xff1f;做到多少合适&#xff1f;现在没做不也挺好的吗&#xff1f;甚至一些大…

MYSQL-SQL-01-DDL(Data Definition Language,数据定义语言)

DDL&#xff08;数据定义语言&#xff09; DDL&#xff08;Data Definition Language&#xff09;&#xff0c;数据定义语言&#xff0c;用来定义数据库对象(数据库&#xff0c;表&#xff0c;字段) 。 一、数据库操作 1、 查询mysql数据库管理系统的所有数据库 语法&#…

django(3)jinja2模版的使用

启动模版 安装jinja2 pip install jinja2 配置setting TEMPLATES中添加配置 {BACKEND: django.template.backends.jinja2.Jinja2,DIRS: [os.path.join(BASE_DIR,jinja2)], #模版在项目中的所在位置} template中各项的含义 这个配置项中模版自上而下加载&#xff0c;重名…

Spring Boot框架的电影评论系统设计与实现

3系统分析 3.1可行性分析 通过对本电影评论网站实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本电影评论网站采用SSM框架&#xff0c;JAVA作为开发语言&#…

基于单片机的智能小区门禁系统设计(论文+源码)

1总体架构 智能小区门禁系统以STM32单片机和WiFi技术为核心&#xff0c;STM32单片机作为主控单元&#xff0c;通过WiFi模块实现与手机APP的连接&#xff0c;构建整个门禁系统。系统硬件包括RFID模块、指纹识别模块、显示屏、按键以及继电器。通过RFID绑定IC卡、APP面部识别、指…

Linux中Kconfig结构分析

目录结构中&#xff0c;某一层的内容无非就是&#xff0c;要么全是目录&#xff0c;要么全是文件&#xff0c;要么既有目录又有文件&#xff0c;我们的Kconfig文件通常是分布在各级目录中。那么&#xff0c;这些Kconfig如何一层一层地去组织起来呢&#xff1f; 首先明确下&…

VTK的学习方法-第二类型应用

VTK的高级使用方法是自己写一个算法&#xff08;Filter&#xff09;&#xff0c;本文使用的数据类型位polydata&#xff0c;这个数据类型应用比较广泛。 我们的算法一般是继承VTK里面的vtkpolydataalgorithm&#xff0c;然后自己添加一些变量&#xff0c;重写&#xff08;over…