ue4——攀爬系统的实现与总结

攀爬系统概述

运用场景

在许多动作类游戏中,攀爬系统作为动作系统的一部分为游戏提供了更多的玩法。如“跑酷系统”、“躲避系统”、“轻功系统”。攀爬为以往操作在 “XY” 平面的动作游戏拓展了 “Z” 轴。让游戏的高楼大厦不再是背景板,而是游玩的空间。

类型游戏

  1. 刺客信条系列
  2. 看门狗系列
  3. 天涯明月刀(武侠类游戏轻功)
  4. 古墓丽影系列
  5. 蜘蛛侠
  6. 波斯王子
  7. 虐杀原形
  8. 塞尔达传说荒野之息

攀爬系统的实现

实现灵感

在游玩 《古剑奇谭3》“古厝回廊” 关卡时,由于跳跃没有吸附的功能,使得在越过障碍时很容易掉入深坑。使得该关卡的游玩体验与流畅度大打折扣。自己太菜的缘故。
而这类关卡在游玩 刺客信条、虐杀原形 等游戏时并没有这方面的困惑。像是刺客信条中的古墓探索等“纯跑酷”、“机关解密”关卡其花费的时间更多的时在 解密场景变换 上,对于失误操作也有“ 边缘吸附 ”、“ 地图返回 ”等措施的补救。
经过以上的思想碰撞,我产生了一个问题 “攀爬系统是如何实现的呢?” 经过一段时间的学习与资料查找,我实现了攀爬系统。下面请让我来分享自己实现的思路与步骤。

引擎

虚幻4
4.25

操作

C++混蓝图

成果

攀爬效果
攀爬展示
攀爬展示
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

攀爬动画资源

虚幻商城的:Climbing Animation Set
bilibili知名UP主"驴肉墨鱼汤UNOFFICIAL"的搬运视频:50分钟创建攀爬系统

实现思路

  1. 使用ue4第三人称模板。
  2. 角色在腾空时通过碰撞检测判断是否可攀爬。
  3. 可以攀爬时吸附到碰撞点,角色移动模式设置为 “Fly”
  4. 判断上下左右四个方向是否可达,若可达根据输入向相应的方向进行移动。
  5. 转角、边缘处通过Montage动画进行特殊处理。
  6. 跳跃系统通过碰撞检测与Montage实现。
  7. 蹬墙跳、脱离,改变朝向停止吸附,改变移动模式“Falling”。

动画蓝图及Montage

动画蓝图

动画蓝图状态机
状态机新增一个 “Hanging” 状态
Hanging状态实现
在状态机中使用一个 “Blend Space” 进行动画混合。将向上爬,向下爬,向左爬,向右爬,静止动画通过 VerticalHorizontal 混合在一起,之后可以通过角色进行控制。
动画蓝图Update
动画蓝图每帧获取角色状态,并通过状态调用相应的事件。
播放Montage事件
当角色状态改变时调用相应的事件,播放相应的动画。Montage播放完毕
当Montage播放完毕时,使用AnimNotify进行定位。在动画蓝图中实现该事件,调用角色中的处理函数。

Montage

相较于状态机,该动画资源主要用于使用较灵活,触发事件较短的动画。
Montage
使用DefaultGroup.DefaultSlot,添加 “AnimNotify” 标签用于状态检测与触发。
State
DefaultGroup.DefaultSlot决定Default Slot插槽。

Character和碰撞检测

碰撞检测

创建一个SceneComponent的子类
用于实时的状态检测

TraceSceneComponent.h
#include "CoreMinimal.h"
#include "Components/SceneComponent.h"
#include "TraceSceneComponent.generated.h"

class UArrowComponent;
class AClimbAnimCharacter;
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class CLIMBANIM_API UTraceSceneComponent : public USceneComponent
{
   
	GENERATED_BODY()

public:	
	// Sets default values for this component's properties
	UTraceSceneComponent();

protected:
	// Called when the game starts
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;


public:
	UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = "Poisition")
		UArrowComponent* ArrowForward;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Poisition")
		UArrowComponent* ArrowBack;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Climbing")
		UArrowComponent* ArrowClimbingUp;
		
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Climbing")
		UArrowComponent* ArrowClimbingDown;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Climbing")
		UArrowComponent* ArrowClimbingRight;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Climbing")
		UArrowComponent* ArrowClimbingLeft;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Jumping")
		UArrowComponent* ArrowJumpUp;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Jumping")
		UArrowComponent* ArrowJumpRight;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Jumping")
		UArrowComponent* ArrowJumpLeft;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ArrowParamater")
		float ArrowLength;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ArrowParamater")
		float ArrowJumpLength;

	bool IsHanging;
	float num;

	FVector hitLocation;
	FVector hitNormal;
public:
	UFUNCTION()
		bool HitResult(FVector beginLocation, FVector endLocation, FHitResult& hitResult);
	//对线性碰撞检测的封装
	UFUNCTION()
		bool IsInAir();
	//判断是否在空中
	UFUNCTION(BlueprintCallable)
		FORCEINLINE bool GetIsHanging() {
    return IsHanging; }


	class AClimbAnimCharacter* GetOwnerActor();
	UFUNCTION()
	void ForwardTrace();

	void UpTrace();
	void DownTrace();
	void LeftTrace();
	void RightTrace();

	void JumpUpTrace();
	void JumpRightTrace();
	void JumpLeftTrace();

	void ClimbDownTrace();

	void BuildArrow();
//箭头的初始化
	virtual void BeginDestroy()override;
//析构函数用于调试
};

TraceSceneComponent.cpp
// Called every frame
void UTraceSceneComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
   
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// ...
	//GEngine->AddOnScreenDebugMessage(2, 0.1f, FColor::Black, FString::SanitizeFloat(DeltaTime)+FString(TEXT("  "))+FString::SanitizeFloat(num));
	<
  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值