UE4-分析自带虚拟摇杆TICK函数

 原由:需要理解异性控件控制,一般的图像控件都是方形的,由于一些需要,做成像摇杆类似的控件控制,将摇杆限制在一个圆内,并且返回对应值。

 

源码不多,通俗易理解,每个变量作用都有注释

//绘制摇杆两个圆形的TICK函数
void SVirtualJoystick::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
{
    // 状态判定,是否显示摇杆图像
	if (State == State_WaitForStart || State == State_CountingDownToStart)
	{
		CurrentOpacity = 0.f;
	}
	else
	{
		// lerp to the desired opacity based on whether the user is interacting with the joystick 
        // 根据用户是否与操纵杆交互,调整到所需的不透明度(翻译)
        // CurrentOpacity默认值为0.1f
        // GetBaseOpacity()如果激活摇杆时激活状态,则返回1.0f。否则0.1f
        // 插值类型为Tick每帧时间间隔
		CurrentOpacity = FMath::Lerp(CurrentOpacity, GetBaseOpacity(), OPACITY_LERP_RATE * InDeltaTime);
	}
    // 以上这个IF设置当前不透明的值
    ---*---
	// count how many controls are active
    // 计算有多少控件处于活动状态
	int32 NumActiveControls = 0;

	// figure out how much to scale the control sizes
    // 计算控件大小的缩放比例   --->1
	float ScaleFactor = GetScaleFactor(AllottedGeometry);

    // 两个摇杆则循环两次
	for (int32 ControlIndex = 0; ControlIndex < Controls.Num(); ControlIndex++)
	{
        //获取摇杆信息
		FControlData& Control = Controls[ControlIndex];
        
        // 更新中心位置,则摇杆跟着拇指位置走
		if (Control.bNeedUpdatedCenter)
		{
            // 增加摇杆启动的时间
			Control.ElapsedTime += InDeltaTime;
            // 当启动时间大于延迟激活时(未激活时)
			if (Control.ElapsedTime > ActivationDelay)
			{
				Control.bNeedUpdatedCenter = false;
				CurrentOpacity = ActiveOpacity;
                
                // 如果剧中
				if (!bPreventReCenter)
				{
                    // 设置摇杆对中的位置
					Control.VisualCenter = Control.NextCenter;
				}
                // 触摸事件
				HandleTouch(ControlIndex, Control.NextCenter, AllottedGeometry.GetLocalSize());
			}
		}

		// calculate absolute positions based on geometry
		// @todo: Need to manage geometry changing!
        //基于几何计算绝对位置
        //@todo:需要管理几何变化!
         
        // 不需要根据几何图形定位控件 or 当前缩放值不等于上次使用缩放值 --->1
		if (!Control.bHasBeenPositioned || ScaleFactor != PreviousScalingFactor)
		{
            // 获得摇杆的信息(图片、透明度设置等)
			const FControlInfo& ControlInfo = Control.Info;
			
			// update all the sizes
            // 校正的实际控制中心
			Control.CorrectedCenter = FVector2D(ResolveRelativePosition(ControlInfo.Center.X, AllottedGeometry.GetLocalSize().X, ScaleFactor), ResolveRelativePosition(ControlInfo.Center.Y, AllottedGeometry.GetLocalSize().Y, ScaleFactor));
            // 重新对中位置
			Control.VisualCenter = Control.CorrectedCenter;
            // 可在交互大小区域内重新居中的操纵杆的校正大小 --->操纵杆
			Control.CorrectedVisualSize = FVector2D(ResolveRelativePosition(ControlInfo.VisualSize.X, AllottedGeometry.GetLocalSize().X, ScaleFactor), ResolveRelativePosition(ControlInfo.VisualSize.Y, AllottedGeometry.GetLocalSize().Y, ScaleFactor));
            // 中心周围可交互区域的校正大小
			Control.CorrectedInteractionSize = FVector2D(ResolveRelativePosition(ControlInfo.InteractionSize.X, AllottedGeometry.GetLocalSize().X, ScaleFactor), ResolveRelativePosition(ControlInfo.InteractionSize.Y, AllottedGeometry.GetLocalSize().Y, ScaleFactor));
            // 可以在交互大小区域内重新居中的拇指的校正大小 --->拇指
			Control.CorrectedThumbSize = FVector2D(ResolveRelativePosition(ControlInfo.ThumbSize.X, AllottedGeometry.GetLocalSize().X, ScaleFactor), ResolveRelativePosition(ControlInfo.ThumbSize.Y, AllottedGeometry.GetLocalSize().Y, ScaleFactor));
            // 控制输入的校正刻度
			Control.CorrectedInputScale = ControlInfo.InputScale; // *ScaleFactor;
            // 是否需要根据几何图形定位控件
			Control.bHasBeenPositioned = true;
		}

        // 有交互 或者 向下一个TICK发送“释放”事件(可能是UNHandled或者Handled)
		if (Control.CapturedPointerIndex >= 0 || Control.bSendOneMoreEvent)
		{
			Control.bSendOneMoreEvent = false;

			// Get the corrected thumb offset scale (now allows ellipse instead of assuming square)
            // 获得正确的拇指偏移比例(现在允许椭圆而不是假设正方形)--->重点来了!
            // 2D向量:值为((拇指的X位置*2/摇杆的位置X),(拇指的Y位置*2/摇杆的位置Y))
			FVector2D ThumbScaledOffset = FVector2D(Control.ThumbPosition.X * 2.0f / Control.CorrectedVisualSize.X, Control.ThumbPosition.Y * 2.0f / Control.CorrectedVisualSize.Y);
            // 拇指平方和(x*x+y*y)
			float ThumbSquareSum = ThumbScaledOffset.X * ThumbScaledOffset.X + ThumbScaledOffset.Y * ThumbScaledOffset.Y;
            // 拇指平方根
			float ThumbMagnitude = FMath::Sqrt(ThumbSquareSum);
            // 拇指Norm值
			FVector2D ThumbNormalized = FVector2D(0.f, 0.f);
            // 一般不为假,除非手指大过屏幕
			if (ThumbSquareSum > SMALL_NUMBER)
			{
                // 限制比例1以内
				const float Scale = 1.0f / ThumbMagnitude;
				ThumbNormalized = FVector2D(ThumbScaledOffset.X * Scale, ThumbScaledOffset.Y * Scale);
			}

			// Find the scale to apply to ThumbNormalized vector to project onto unit square
            // 找到要应用于ThumbNormalized向量的比例,以投影到单位正方形上
            //同样开平方根
			float ToSquareScale = fabs(ThumbNormalized.Y) > fabs(ThumbNormalized.X) ? FMath::Sqrt((ThumbNormalized.X * ThumbNormalized.X) / (ThumbNormalized.Y * ThumbNormalized.Y) + 1.0f)
				: ThumbNormalized.X == 0.0f ? 1.0f : FMath::Sqrt((ThumbNormalized.Y * ThumbNormalized.Y) / (ThumbNormalized.X * ThumbNormalized.X) + 1.0f);

			// Apply proportional offset corrected for projection to unit square
            // 将投影校正的比例偏移应用于单位平方
			FVector2D NormalizedOffset = ThumbNormalized * Control.CorrectedInputScale * ThumbMagnitude * ToSquareScale;

			// now pass the fake joystick events to the game
            // 现在将虚拟操纵杆事件传递给游戏
			const FGamepadKeyNames::Type XAxis = (Control.Info.MainInputKey.IsValid() ? Control.Info.MainInputKey.GetFName() : (ControlIndex == 0 ? FGamepadKeyNames::LeftAnalogX : FGamepadKeyNames::RightAnalogX));
			const FGamepadKeyNames::Type YAxis = (Control.Info.AltInputKey.IsValid() ? Control.Info.AltInputKey.GetFName() : (ControlIndex == 0 ? FGamepadKeyNames::LeftAnalogY : FGamepadKeyNames::RightAnalogY));
            
            // 设置焦点为活动窗口
			FSlateApplication::Get().SetAllUserFocusToGameViewport();
            // 传递控制值(值是轴映射)
			FSlateApplication::Get().OnControllerAnalog(XAxis, 0, NormalizedOffset.X);
			FSlateApplication::Get().OnControllerAnalog(YAxis, 0, -NormalizedOffset.Y);
		}

		// is this active?
		if (Control.CapturedPointerIndex != -1)
		{
            // 记录交互的变量
			NumActiveControls++;
		}
	}

	// we need to store the computed scale factor so we can compare it with the value computed in the following frame and, if necessary, recompute widget position
    //我们需要存储计算出的比例因子,以便将其与下一帧中计算出的值进行比较,并在必要时重新计算小部件位置
    // 下面就不分析了
	PreviousScalingFactor = ScaleFactor;

	// STATE MACHINE!
	if (NumActiveControls > 0 || bPreventReCenter)
	{
		// any active control snaps the state to active immediately
		State = State_Active;
	}
	else
	{
		switch (State)
		{
			case State_WaitForStart:
				{
					State = State_CountingDownToStart;
					Countdown = StartupDelay;
				}
				break;
			case State_CountingDownToStart:
				// update the countdown
				Countdown -= InDeltaTime;
				if (Countdown <= 0.0f)
				{
					State = State_Inactive;
				}
				break;
			case State_Active:
				if (NumActiveControls == 0)
				{
					// start going to inactive
					State = State_CountingDownToInactive;
					Countdown = TimeUntilDeactive;
				}
				break;

			case State_CountingDownToInactive:
				// update the countdown
				Countdown -= InDeltaTime;
				if (Countdown <= 0.0f)
				{
					// should we start counting down to a control reset?
					if (TimeUntilReset > 0.0f)
					{
						State = State_CountingDownToReset;
						Countdown = TimeUntilReset;
					}
					else
					{
						// if not, then just go inactive
						State = State_Inactive;
					}
				}
				break;

			case State_CountingDownToReset:
				Countdown -= InDeltaTime;
				if (Countdown <= 0.0f)
				{
					// reset all the controls
					for (int32 ControlIndex = 0; ControlIndex < Controls.Num(); ControlIndex++)
					{
						Controls[ControlIndex].Reset();
					}

					// finally, go inactive
					State = State_Inactive;
				}
				break;
		}
	}
}

当前类还有个OnPaint函数,有机会在分析以下,但是我发现大多数使用了废弃函数,如果要复现起来也是很麻烦


(拉吉CSDN,发发发NM的发文助手) 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值