From 94e50e570797b58de6f46777a2ed7219b8f097ae Mon Sep 17 00:00:00 2001 From: Daniel Rupp <daniel.rupp@rwth-aachen.de> Date: Thu, 27 Jul 2023 16:09:45 +0200 Subject: [PATCH] Kept initial PawnMovementComp, but separated continuouos movement into own component --- Content/BP_VirtualRealityPawn.uasset | Bin 33285 -> 33540 bytes .../Movement/IMC_MovementLeftHand.uasset | Bin 16883 -> 18884 bytes .../Movement/IMC_MovementRightHand.uasset | Bin 16148 -> 18151 bytes Content/Input/IMC_RWTH_Base.uasset | Bin 13313 -> 11270 bytes Content/RWTHVRGameMode.uasset | Bin 19364 -> 19364 bytes Content/TestMap.umap | Bin 42864 -> 43475 bytes .../Pawn/ContinuousMovementComponent.cpp | 233 ++---------------- .../Private/Pawn/VRPawnMovement.cpp | 193 +++++++++++++++ .../Private/Pawn/VirtualRealityPawn.cpp | 177 +------------ .../Public/Pawn/ContinuousMovementComponent.h | 103 +++----- .../Public/Pawn/VRPawnMovement.h | 73 ++++++ .../Public/Pawn/VirtualRealityPawn.h | 63 +---- 12 files changed, 317 insertions(+), 525 deletions(-) create mode 100644 Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp create mode 100644 Source/RWTHVRToolkit/Public/Pawn/VRPawnMovement.h diff --git a/Content/BP_VirtualRealityPawn.uasset b/Content/BP_VirtualRealityPawn.uasset index de6a205060c6131ae6724b3246de1ef437f2b6ec..2870c55ca9d0135f07db10a523b0f6c111a92caa 100644 GIT binary patch delta 11247 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 FApoN#oVx%3 delta 10996 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 diff --git a/Content/Components/Movement/IMC_MovementLeftHand.uasset b/Content/Components/Movement/IMC_MovementLeftHand.uasset index 6762960518fa317c48d0effb0e173a6f09f2e763..155f287eb0a79caf26c6539da0dcc303e06309b5 100644 GIT binary patch literal 18884 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 V$N&&7yJr!|a%#UOY}X4&Jpg)+LpuNf literal 16883 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 diff --git a/Content/Components/Movement/IMC_MovementRightHand.uasset b/Content/Components/Movement/IMC_MovementRightHand.uasset index c848335f083150cd0393bb64dac0495a9aaa949e..2af1ca1edd6584f443c7b266dc06c62f35e716aa 100644 GIT binary patch literal 18151 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 IUjd{Z0N`E%&j0`b literal 16148 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 diff --git a/Content/Input/IMC_RWTH_Base.uasset b/Content/Input/IMC_RWTH_Base.uasset index 9f2e4864bdd16cd30a452191d9ac298cd579e460..90c92e351646615863813e7c77ebba0c3cedd8b5 100644 GIT binary patch literal 11270 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 literal 13313 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 diff --git a/Content/RWTHVRGameMode.uasset b/Content/RWTHVRGameMode.uasset index c3904e554dfa66dd200f0e61e318efac52b09a3a..72b55a3feed2c36b8d8892016be9e0dd513d6232 100644 GIT binary patch delta 31 ncmZ27opH%@#tqGk0%f<3ojt@??c09Ue~0do606OV83nxn<&q8D delta 31 ncmZ27opH%@#tqGk0*}raC{A`Nblu7PO}pOo{L{^o83nxn)TIqD diff --git a/Content/TestMap.umap b/Content/TestMap.umap index 7e7113328a4bc24bfdcbdc7f61a83af3a8cc305f..eb51ef631942a0ef7e8ae3c71c0a0733fb8e1746 100644 GIT binary patch literal 43475 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 Nzb0tGD2NYI4*-B~4W<A9 literal 42864 zcmX@utTpe)|Ns9Jm>C$jm>3v7Ff)Jw9|Hr!{O%t@f4oXNcy87#)7)!iq07L)@WtbT zT!xRH{*vGeow@@39~l`K819xn)l_#|{GjZTz}#1Nbd&`d7#M<LZ$)}|8VOZIR_y40 zxubxCfq`K=n@{u)uVj^i{m~6~FMK`A#lXPOCLx>9;-9kS-es{>*N(s94PankXuMjR zx!TeH*_%MGRT|s2?~7nyU{JamGH0K^+6p&z#VHq>wj}B>Ffd%(^M7sxqrYd9km93` z6_ad0=E+Du-u6at{-xIWb*+yIX6A$3XJ7K?e1ppd=ldcPCl@QoimNg(FgV4{zTxJ( zS7pT-p_WSVl>3?t3=D5GHavOhH02BTEyG2QyWR9O7#J8bk~yA7_$X%=NL#i{j8hY1 zVPIgG7sS9I&cMK+9~2(q5f&7ZpP!SRS)w13T3q6rSir!*z{Jqa$iNW8#J~Wuex42k zgCYY1gSnZBi<y&?i;20bg{7r|n}w6HrMZcto1wFTp{1*{8#vrI=`b)DGcYg+Su-%i zFfcHH_(pyZgX{ts7~BFG7{US>7_NyPPc(XQ-)BkhS^jp06;I!`tf*dLAK|_D%W3}f z@6#rMEC!haatJE}BLgGD*=;$DLJSNH+S;M6rrJTNIjM=osk)|mh72Hi28N>R@i^qc z4g-bH*)_c&c1a)ugUxaf3xWUt|NkEpF7}KJ3=U8^Nl+LCCl_TFl<4~<mSv_VmSpDV z1y>fAq~<cL+M%KkiZI9IlKdj~(##YF_q9sC+zbp1U=g3hq|_XS<>E#0JRqU;)Vvap z)XemZ5{9Gm7j1@%1tq3rmKHOZzb%de+2)v=l$n}W;-8$HQ(ByvpXZ#PS6q^qSHkdH z<k}P&kU?k)LQ*SAN{dp1GpkY=yu*_I2!qt*Wftd`6y+CG!nJdkC%zR!kwVtETrG=3 z1SDHfP?TShnVVRW8k|~El9`uY%#dHP;vrZkTrM*|&oMc<v?wvTk|BTni&fx2C`wIq z&PgmTW+;+glK{$ljzvX@l>tTh1*t_Pl?<L69%q7srl=^t+&Modzlh<3Jx>ll$Wn+< zZb5!tYF-ILXh@nJFG#qgBr!Q7Ah8G}sP})x6Obd4z(MPpmzb23>YSgGlL-nV2E&fk zULZ#}C8h)y6lIpAGHl~iIRf%fl4DLzez{8~C=8QR-7-^iQW%(axX4K`Ffc&mf(ufU zGt)AYT`Qm=&d@bC<Oe8oK;%Qp^Mf-}Qd4{rOHzw66LT0gzg=?(6vz<iu+*ZG)C#bN ziWvl@*i=NpCZk0XC{yu14LJnzZjvKBc0j_)=2BXq#Nd=zoa&rdP>`9I&S0s=TLZGf zDX};+IV{LCuOzi7F&UKf7}kC`yBXrRl9JTif)dBllKha2%;fCUJdn;KQ(i3rg+vla zJRIcP=iIlP!6E0An4Jo7txIA_Vo1JkYH<d`DUHjMq(ClqPRvOz%}Fdtb<Qs;N=+{D z@ptjfPf5*Tu!>4?0j0Yn=ltA)(vs8^A5a?hO)LmXEzZv=1v@HNu;+j@*c6BwEJ~(* zIQ$b-swO!XrGjmN#hu;C?Ehf*K_q-ri_(z-+xgjqdQf6Wa?Q;wF3v1V1qGRBz&ayP z@PGtM+)8tDTvC%t)4~3UjZ8TX%0@|$BmxQrAAcA3)V$OpaMoqG#%f>2334h#K?;Lr zZuK;<+aUsArw3;wrXjK*!~5DrQ@{xZq6DKLV6Cuf0eb-=ACOp-n3I#5<CK^UiW2n+ z2fM*B29XWU%q_^tOsfniN(}&I7j=z4<=`~qT3iCocpiyGDSr7yxrsT&3=4GFc)`)> zmYI{|o>)-Kpv3?34me>${geuJuy0~PXc$AnHHDdAqfq2>L2|_m^RE^D2Ky5x>6e(7 zS&|BIR0=roGE8%F<w0TNUX)*2;F*$|SCW~Wm;;haEq2Q<f_mttP3jF$WtilVnUa#4 z$5401lM5WRp6Pk{MX4c~d6fZ)MJ2@yzs0_Ug39Y8&%ETE(v(!s+=Be#lGLJNhRsRd z+d<Ll<m2k+67OG-SXi3MP?2_H4al=jIjMOmpv1@U>pRmT0Z>(!lb@XJn3LmDnU|QG znaprI@%sdjUz~DEQwxeR^GYCTCk2#5!G%aMgPuz*2RLDa6O?OVX=YhsPHJ8WEE^Xy zsO$<;1{t0NR)G*d#n0CYb~RW$AfvK4Gr1U)Wf;Cs=HCi(b&_vtNn%b;W-=%-UU#oQ z2{y(rwZt(cr6{$y7*sehm>#yR1QmEmkhlaX?J}CT5u8r^@=M(Ei=1=7C4EtFYEfBg z5re4WhArS!4KDjrQr(L3bDi=_O7e3VqNQ$mfh=~)PpR|-*9Xa|3=U6LoK*nDmVaJO zB`i{%b4tM>?3P~?mY-9an_A59W$ANPP<iZ>pP!wZSd<Meml@JSq`DzS=I6i*X#tiE zU7)fk$-f{mIkTh^<mj(cXRv_%2Nx^O28r8#zxf3m!2V^aMMaq@sUby)dBtg|MX<t_ zVe!S2$q)}gRfOeNq~?Gtswun9nu5bPAhRsLBp^RCuf(w=Dzzw|VSW9pc93h60*X?L zK>_1fl$yw}oF^#;oazHWu?@@a#fj;u#SFItZe9T=zo68_oRG|1P$>$k5g8tLG<JbC z1*Im#N;gPk6f<}wGadj(MNn#KaVjW<gYywIuiSgGR0>??fn@`VQp+;)ON)I{%TjY- z0n8xd^xPEe(4hR%^o+dJ;$l#!Tv~5`mkpF+i%N?#81%l1rGNt&#B(am%t=WtVyI`} zYy;H;P9Q;eie=alnH~xb`{2}^)Z`Ly8WP_uz7nKA2~<gy<|Gz@tWfq{d=y;71(zh2 zWF~{%otc*oGQPw;)YFB*Zbr5UINXCv3kvd!N`ewALy8iUL1mHdg=G*+LK5>p4HA%f z2}{oH1X&C+ASJaZAU~&);g;-j18_+aTAb>VnwD6aQ-Y{%3%6M>0~cta#i^je$}ulJ zCp9FaD782vKPQF3@!N;pFugvBc`3!oi3O?7r8zku2QU|G5C%Iwv^W)(a9oNK;WaeF z&$BCzD}hpVXmKjk;i)OGBn7U&gEJCS^2>`EH2-?)gQFLuGBqzHwFp#ar50zT7Bk3r zxHW(iZD?_7NNR2YsPr!_N@cLLQ#}q28n8IH;pCK=2d+66zMZiNoSj08QxVl9ywro0 z4-7LN2Zn$vkg&|+%%q%DhAq|m^+1v2R9TV=&q>exbPupIFfceL=B5@UGBmGS4R#NN zi-`2}%9f)bz0Qfb{zWAj`BC}#xeR4RwmU!(;+&WpkYAh$u3@)3i?u?<g7QJ}o}b5{ z^x#+~sDyD&%ndC_Ni0cCVMzI`2Cn{`6AOw<p)I78)FOn13tuPHgE9+T0j$*}*5F?V z3K^&b%o4ZE3Wg~&ZKpz|K=}$B3I1tenW^OrJ?i2UK~;fsMq*xGY7T>x!mnqbIC0KN z%q;+CcbClE)I4w_&Faee$6%{r%{FM&!@$DuX(K4Xz*AU2QGQxxPO4vGZYl#OhwVI2 zNdcD(N-ZwP&nr%4uxebn1MDoAc`%t`2FZ-KuR*yG+$>{QGch$CRIeaHVfMuB;-LKP zoS#>cnOB-$TI`!&mYSQISAtNp#JwUFluf}^OJ;taZ)!<KehNc-c~K}UC}K;KQW>_( z_{D>rP+C-$2nrj=oXqq*kU0$B%l_T~r9f!zaZk)m1y^Yyj(gvMw78@eXBMTVIOUh- zr9is?3lAIZ2jvZ@lv^e^%LJqrC8y?<B&Me_xG>Js0qf07ODhE>Y;Xbw7pU<btG0st z=#mL)yk+L+G1R*j>4C~;xJY6SxTrw*@OY?ZJ;XS0jg{h51ZvrVN-~D$K1EAG0fZ&v z!Gsvj-Ac{{<y2^;49S)-S>OCJPzeUMkzvVdbzx9Kbw$+d*FU!W2PFnqXXp6v{Gyx` zs3{EH;X=1T@$Cwaa9G;%$uMF<m4PLo`u-`_pmqyF4^+m=$}b;o4#SL`z#kz0B9y^W z41@8-*Sw&hcZG)zTC{V1D&YimMsX>yvI4j3Qo;SLqEc{M9nx=P;9rpP6KX9qv-##H zW#(j-R5FD3q`U+LGs0Aul$8}U1R4I!n^FS~Jm;WzNCS(ZOOJg8s4#F%$t=k)0%gQv zhFOvF3ZU3<^~g*uN-Rpw0JYq}ZUS{~z-?b>3QmZbvkNp<Kv1QX6}Sb&(74e(4%FIm zMK8?*ic*sy9k87T6i$N%2yiR0vhv7G&tPC;Tq*+&3|M&zwj!jmAeA9eNAf(_2cX*6 z5xKL8)HMRDeDz}QeM1HY23JBVLGh2Inc;Wrj}p+Z3#LX;i#IPNASW>|)j1~<+zSiH z&&f=#WU#dOvBD0kWjOVKtc6Iz%wiBf^3y^ct0|~)1hw>=%ejZvL@T$la!<|AO)V+P zOb*G<Ni9muOHO6jrL)iiR7+#}6&!{~EnT02QvpU8f}}xFU!38X2k-S3GvrU}Gyn}d zVVV~j25o(2=I24(AHTq%7Mxu$OvhAgWff4AnwDA=;aHNBSj=$o!25Vm%M5IfkG~6~ zIh2{72XYs~iu&8qDzJb-m$kBj_hNngT^Npv%3lOkMzF3U@_@(I)>bW0#p{|^nhUSA z1Fz3@0H<PT3p@oHtd(w=IiSveUOLo!ODoGagQJIlLMtn9BLSS*LFq6BZV<!UA6H(; zfjkmWlwVN^X_kTtpHfKW4$Z3;Q(fkP#w=a&sj{*Hx4^=|gG;F?4D)msE>Q*<9bAxD zo(CQ<ffs@viFqlYh8Wa*u?J_a8xW<`%E~dPJh8GEY$n5jtB>@-*%%R~nR)5p7)oCB z<rk<Xat#ghFD)r3Enx_IW8n%eTwx+sRuCCj$zJ<%`!tXOx5S*Bq{QTGXq6XIl$i)> zS{5^O#_U)HN)s>zL8&>3C7ETZu0=)pMGTTbqSc_5xLZzsVhKDle=ooH7gTP#<)^!V zS|BBr4DZ)9Ye0lR4e@})k_?8L=3a17>Yi8ttGXCGwk#?Ec@7%;naM7xWtrd-l)*eS z#u8+LdwxD_q$x4=ayqD;fR^Etc-FrIIT=+r3OWL4G%G5Xm4Sf)JZk71@GApsXlY4F zY7w|PpZPBKD5!*YhX@rUCZ{qqmlq{~oQ0*yz2e+eHBe&%Bn3%I;1t2|;rDBAkTo8u zi75<cHgx_3HM5W_2yhN6DJ@_ywD`;lD&vtQQA;L<V!gYnp!(M{FS8^wF()9gBss%5 zzcjCeVcFjglR;4q8mG!D232hN=h-%c0tF-j9k~ihtYm0OZo3Z(6jWi?+)R+i83Na~ zEd;f!J@X(vLWa6hPcBd>fCOOUh)XY<d4Uy`q~?Mfi2vMgwt~Fnotj#Jk#Ov`q$~n8 zf^gSdPyWRH1~nCZ5-U@S7<$@Hr-Pd9U|uo9rGWf2kYzrpX(gbX!=S>&9{_5$fV+a= z4iji#z%zwmrcPl5C~&|Mpc)y}@$$?|%V!8q+UWoa3UE^hl*7RT6bw2Br9NPnf!bVd zrFq~MgIi)sDm)q5|F#D=yTKY^DuR;}b5a>3Jk<-q?gD8Bb*nUYJAMGA4X|3&u{o(1 zp~YY)gVYA+mlh?bLK4TP)4r>~hU6zh5_e(EhC^VL=!Nd~$15#Cp2MuOGisu%K)%3` ziHEj(8GLhRRf3v0m@2@@t1>-5kD=vOL^3E@z|?>XJNWo>^Cxle$RSJ?E}`u8Xg;Xf z2bU-*N=?ko%u9zA4^H_Nsl^Nn#Z$!~uCD-l9FdzRpZy7L5c(#9WI+Avu+*G<(7*?S zBGcP#pjh)wtO!c1bWSWT0mTc$r~k_tKt&C>)dCU$SG6naGUtIR6R;@Mc?|Pbw>p7B z6C?;K8{z$9yMvcbgTpMfI0L1b1Jzl~P<%-C4X8W>Ri3_y6~W0xsi}FOasisY86rNq zmw{?Fu!7X0^vt|;xaPR+d%z>#V7bgZl+JbcA!Bft2_y#@{)1~fdnf2JIFwS0Gf>0- zymDeT#3PVFFK`nVG$Uc~J>WFN6%YwTU69J~W8#U6U@v6m`IY7-r55?8fh(fokbH2q zVX%~Gehx}~um&%~&R?w4K^YO$OUhxmWHloVRHFHo=9FXxCxV7d^U@t189rYT{|E|d zP}YYR^-Z5Ryg-E)#7kh;!|D!Lh&{@>_5u{25G8P5Z~vaV2$XO963ZMx;~`KZGgFHh zCUjqn1w}QoR563&&tnmwq>4TU44L}axhR$$)aJsF&Cg5AOlO#`Bbg4h4P_=N%#b0c zZ<93Gw$#KTa4Qs)xER#sERTZ<K;&M`Ei=={pfcSrKQEQx3-eK4(8x5T(1*2t5WQ7v zUWuQeScS+VM^MjPSy@nk_$OthCL?N1$J?7<f$AcNFt|eR>y`lz!h+j6pq@Om?Qrms z`8H4#LB|E*$>M}t(i~8-fQtJj7H7ld<|wyyfdU9g4%ty2a+h2{0R)vsmioDQW*yjJ z;5G%=VG1Yfqe0aUq%jd1R?KiFCVmO1F2Fjn<S?n^EhsEtlCWZ<nBn2J+lOTt7#IQ) zld}`kQ+@K26LT`Fz=a|xofU(tU!ju94v=jD`8kztIf?1T48LR_Xn|5JNTitIVzKi* zknyk~8${=5#p&1J0U~h1geE<Ppc<hnP_BZNRUk{jBRw4fqB_VDu#p&s-Fxn8g2Ef7 z16&mtyD%JcHC+Qr13}<1Fz3Vq&_D#z<V?}cUpqiK4c^&3*Ilj)N^39y$bhi3N=+`r zc*yt)tZ`QJ&8H3I?;ue90j>liXPK-7>(9?e8ZQyqo;V9^4QzPIX+p(u(AW^z1NlV^ zU70&?fC30UUJ6eY{OpMxplE~3AV<7?ZNEJz;t{1FLwnMLy&(1A8U($2t0-FW36!v* zl9kZZdRw4e29)xGvnw4-a`TG|GE$3D5!JET`32`dehSV{D*@+aaO-gP+RVS8gaK~! z;%Y;m_*p6h%A}w%T99KvT@Qt4kK#d*2oeL;D{!wC@g<~!G6zfo*{6J}yfvU0fJ|W` z-1a7q4cwB2jQ4`dZU&)9hY+wapx#0<NC=@k@1v^{sOUu~cS$YEEK5xRHC4P*D;ZL+ zWP``PgJJb0)DfV@XfcCE=jv{-cS?$&rC}w5^}!+)aF~{WhBn~B1`Kn+)6LMqWT-Kq zii%;D+y8waM}#C6rKgr)X_kb3d$<8qW<wPCX69w)mgWYf7H6iU<|S8p=6O3YFs(EQ z1cg3a33#3pG(H8c6$)}PQ;Qg`?zkj^FefCnA~grv+z&`C@=YyCEn>)No8Sp@J;a=l zqD)AuRqkoRbdX1poqg`DRu(9YBE&#dH)wPs>(e%WPzN4ECO)({H8>O0PeDkfG9237 zcL>zIgNea{8k8?VO)yAUZ|4is0HwN+jMChsyu{2LaEo!1k1=?P7dDXw3Q!~;f1bVc zFDUhc=Uc#|!$?^}DYfYp*hE<02^0zpd+n-q!QLv$%!L&nkiOIWD~~^c>a$Si;9&6d zHniOH%u7kFV9<UNJs%Wup`Ljq#zydXzo%p21uAhu^NK)oz-6iMjxuDxHKK6aZBQ|e z+}DR@!`SjfaZm$0EETk9f?=5qOA5%jkO6nkyp+u3)MAFO{hBL4MF~h0EO0aG*h5em zfapy#uuWA4r*g<FS4mN3vU5&;DPjhYA*^@fbx^ql9)$)4Aw%Zw^J_twGCVUc1r)9D z7MZB`=@lSXfCnO>1#~e3OXsxXTA=kGu6gO1d8zsk3SMjIgH^j1Wx~fu7-UZvN`XeO zph}@saCW7>Z#=j-N)67gbji<6We_>GDihRng(`tkAeF(s@xj@Z!QkSFfk_}_zBZB* zd=m>mvl*ai`eOZH-*^}&-Z!xz-Yq9Tzlfo9#)=;nNLu_0QuDwrg{jqt_l00y(f9R? z4=Bn{2Kj~INc^@)&@d0$${?qJ_^`~PlG4N+&@5YKNo7D{c^*T`(@mZBAj?pf5y8u% zVtv@Sx<0<4_VYormVz=1nw=0s;UnicJhOd3B{-TY*qSAWyYtmRMWQ}r*j3*-zbG{n z(u`sF;i+o}O2;rcNK`VkIkb9$5<g5BVj*-f6a)9!uaiN^1ttqh?TI<ADGWL+(>Xx( zz9VSe3PZ`Ce~Uq-Hkb$ZxdFopj^=bwHU+QYPzVcBK<e}|tYGS#1nL!mB~cc5z)fKI z|4XbDl#84)b8?dM6N`}2_T)Ri*+3Z(KK~6JfJ;pQ*If*nvkP=V83;7x>zi1V&Cry~ z&jr?iEgIvU8NQ0Gx&-nB>YStj1Am^~Cy+RFRtQ`Lg61$=Y(l?+f&gM&NqNOYP)LEL zK`lh6a)z0qRtlhq#S{7Q&J67_az8;sk@!@(yZXh4IR<$;I{COVC|q@P1C`v)rAeva z-b88<!_D-p{fZ0>4A6dOd_2|^8}H0;*Xh+6P+CAJ1kJ-T%=(tM4%91y3!~4QFz|C2 zx_~?bSK(R#S+SIvm;)Ksam!C<@ZM$`4vKcTs(>8O$U<;QVo?c0-rP6GKuH)biP9Qj zkSP@U04k=DrNLDvL#DW2J*YZG$iORpM{q$}?;xLrq5!R2WYFxBiU!3IhPS3>1kMFH z7^`nK1nI_t{EST!ky01FvyTO(21p5XA*TX7><SMPxIzPl8&{t!2c;*Zyr2LY7@FKQ ze<7%_1`V_*fE$@sarwz0Gr<EY3|Tr8r-1Z<Lj%b?mD>t-AaV5aHJa&)Iw%9cia3V1 z8$KC=!UrY*TSWnHn6X$3tp)2yElC75lo*~gY?%y7WXOf%T|E<UpB~gFEJ{s`_fIM= zNlea3W%w1JQ2?se{EITvGxHd}e3+&UYWhMu6b!}g9ikv-LiwQOBVaq`>MThGi>DS9 zXBL;F=9NIaTg#+$24pvK+6nL8eHT;*g4^McFq-GW0q&VY$}Lzy8Sl*CzU1f!P#O<T zPR&DV<a$V?#DnTN)Ks@S;BErQ=fT;P;NWH0>GgLTC>g>8;Ni`{SKqA+Dv~f{3>cpF ze^3T>%u(tu+x-7BpaK?qRdxF4!$44=LE5_veYOlwL4gM08ZoFZw-*Nm4x$|kN$NGs zv8O-@79kFIpaH|5mEoH~hQMkC<LQN4LD@PqFS9JQs5mhPv=Sma6{##;w~1c@WDR<T z(K;Ie9vB2yo(zhy(cnQOFb`Bw!V(gLv<uThP?&&aP#bb@^^CG%>q|ev7z_*yo}i_z z3=H6rB#`j$|NsB{LdCv-1fUpQ-3cPqZTbKIzYh`SZT$cLKPWwbtV6cf3#!*2N`L(S z|GyuUjjRslz5uA)vH$=7H$vI?)PdYbthy#5%mev@81vQ>>As}|)CEG_wCDf-|G`i; zHvhuZ?f(D&e*_WgcK!eVzY>c&7pNG_E|9&^P%&)w`hy~rfq`Mi|NsAE@Td!fs{8Q& z|Njs?>QbQUK<OYE%Eo4I7F6!!|Ns9(@t6lw2TBLwSk!qy#loQU&j0`a7eLv__M)o; z`4?My#-<LIW(k=WM5Mj2FehXlEX)b1gM~REb+E7`q%MU>f7C(akdS$)M4FdIq`GV( z)x99neIJNaS5Bn8EJUiSB2ry7k?O>WR98c!x>_RDH4~{$o=A1=M5?nUQe6j;>g<S6 zxBdVB|3yTo+xGwee^{M}FMoj4l@gKuK<e6vuy^bK|No<iRM&+?ohwufUI+dE|34Bc zhU^bmeGV%tK;>yH9(Ay?0@N<a!J`gVR)EZl!=nyXR)E?O8F<v?LFEqq|Np-e%Esmo zn7RZ1|Nqa$qYk{qih+S)@Bjb*3$dt!)gL8LIZ)Jsb_s!KWP7oxbAak0q|T8@bxuU8 zb0$(9tZhNaeXuk{NSzyz_QJx7ka@5)Nk|<iE<l)&I#}D5kUDQH{(!j!R%d|Hb37h( zu(|-$Zi00LknM$;hpes`k9n{<17vRk9(Axf1Jo{tv9Z|;t2036CE_s;R%d|P&vkgz z$wB4z|NsBL9?HgMFHGIO|Ns9t;86#wgFx;}!lMpW2Z8!gnM9~t{r~^}7A)#uX#-X! zgW_!`C{clSjY4S<g-u-+k>*ukQ3p#0usRat-()=MV09#@p8{hehx4od|Nn#B3BsVM zVp!jjgMozs)YS!vgLXQCXb=Wj1;a2thz4QMu1FA#jFHU;^~90QPl7637X)Q6Kz4qT zYd&c73D%bdxgWF|4rH=GFo=X;nAsp2Bm$#BY(nk_EtG@x8IaAlrNI1iNZ}6}6M^-e zLFTuB9L2!EkcDJER0zD)7Q`mx{+CGRgN74feP59Iu<&_@WIo6|7$((xQ1~O8?+!A6 zfq_9f1j-;Iev#b|G9T8*2e}_+eiD_;2gNV4`(fd;l1k=-=1P#whvlzpR5D*5w3{3h zc?=8;pzwjY{}~15zd%YqMxdSUjF3DE8aSH=jaK1MC<6-xbq-htTmJfjWIkxn6*O+a z40b;Q1FRh1NP+p!(aZ<+y_ulq!`iOG;b7;136Oh17|emDR~Q?c`=2414=NjAV<VvO zp8(ZZ4%*TWWrNIyVUQ4r4WdC9oB2<X%m<YZurU>o`LOt9j|AyP#V~VWG)NYk`A?9{ z2MtZa#$p&4SQyekniv=uOsHf&DF4F7aFE?UivsgMBe@?GKCr$N$mudr&mYHPK1d#f zp-MnZ25jMT8p(W6{DS&cp!5mSpb4rl85kHIM}c_QF(LCGBbg6M|DZGp(gVt0wjc%r z0|QS2cC$gEP$eKHR`)+bG9Og`!unpI@D~7O1kf0BB3L^L0W%jygCwzq&qE~hLGB0j z-#~gm?*9$a#K6E12}`t4J~9PT3*%!m{{fQup!y5e*8{n~45~2%HUI|YgD9A}Fd8I= z&HVdF=7aW$ltDFs+`kGMKBusl4>Avgp~^u_tl|F}$$XHaQm6)y(T*Si1_p+bbSMK_ z-awTg1feW!?!Sj*J}CS_<r_#j$o<Pe3<d^<tw`oWh2RvjUBs9V8dC$E3Ia0!6x5XH z3@8H&MacZSNbU#KFQBnFm>yX8sAgg@7%Bu)3*usP{~aXrLE!`HkAcD-<bH0b<}?b- zzl~--XzUMUEXaIV{ay$gcm+8U4TIFegs{0EoB5!LFp&8Mpojp~`4pIc3(5VU@)Oqg z1m!PS{jxC+=0XGwb2p3z$zXFoy7{m^E699Uv3!pL^KT-#9~8f!elN&Ppzsj{F+fMr z<bzy?9Yd9XC9%2x29o)p_93i~408V}ur3A$j{+zIiGrC6qd`*G%)gFgKFIx`el|!C z$o=m@niv=uK4CE*Dh2NcfcV(VzlLN!sQn4+lY`tp2c(ICf#G2xlz~Kn+yLUjXb>Bl z`B#z52f05TssZHwbs$X)3=FkJPzDwXsvImsjQOB`J}m!&$_kK1?P3s#9TPJD3X=Ol z)j4cT02Ds$P$Q*FpbR7mW-g2dNnvw8viYDjfv~XzkomUIhQuN&nGZU_3E6yekcSu; z819#YT!)Hb?uOAIS#0h<gA_iX@&Pu+0dhaAd=RSz=|;scb73?{mKgJ4V<X7sJ5$ko z*q92k`2`f1e;Fx!K<OVeE(7v2DE)r}d76QNVJ;T)p;83%?<FMjLH#?}7!Jt&u<~;< zY;YZBD6|~`;)2`)qCps2_+LaaAEc%gssXfoL>N@jFfcH@!D2p0EeL~@gD{AV&HM{U z=7YiqG{*wVzlNYiSPTpd|64)2v16FoAX#kYpF%Pp)P4iaX@K;A!XLCO2BgmbdO{b7 zjgCQTVPe?K2UW44J}PK@4>V>7QUl7ipm~gc|Nn!JBLeY3^V5I-|NjqK3<KhW##8_N z|NkGf0Tr}13E2!i1_lPuA~ulSAhn=5j9>r%{|BwQ1Mxv-{X{Yg#0Q;PhivwDsM(;f z1dX+R`~UwxNH1ud@9Y2n|3N!7LH+`*)&bcK>f3>~GlT2~<y%nE01AFk8wIou6{Hum zHX5`P2(&a3#0SmwzyJULKS&%o9Nzu^{~x3WCI;$*f#&hw{{R0U<Q|ZF-~9joA0!Ww z1KAIf2dyasxe25Ogh9)FKr|>Uk3;o>!T=OrAaPK*9R2_QKPVnSD<DDbLr@<KRE~oB zGNAexRHuRZ1)#hED*r%zOi(!mvIi8tpkq2fG-w4aNDSmAkl#RI2}<6ebOI6wsW}35 zGswN5_}={g|9?=Jfz-pqHbKJ~6t5t&K;a8=D=5A<K>eV`z`y`np#~BM#m&0^|Nn!` z2dxkW(V%6zpzw#82})P1{{R0EiW`ubpfTr_|NsAA^Z)<<Lr^!t#Mb`*|Nk&l45oht zT6}=qz8s6#GN>5HU7+*<%Htq5D9tQ^x*fC=8<bB$eg-Y5{{#(xP#EFDAU}cP47{v~ z0TiOJB~@O53=D11(Or-#WI0d_!q&?|7TM}S3;+cUD5(S#W#%RpRXP?Ir<Q;>@qoex zbP5f+BxvIez9R}j=^4CO4t#<}F?{<B$f7U}15E}{Vn9;hS^-*K#{i1@FpUUXBLhoI zOH&IyLrWcnNEBX_t)ZE*g^7WIo`HcT11Q<KB$j~A?#N8bOif_`*=uBAWUOaku4iPX zYiOuvVxnhg0zT<b;K%&`|No!+|Nqy2eo)AOF!H!OD6BySf@o!sBm-zf2E=1vz}egZ z6;7ZG3{v(TL?CHm0OdAx8*nNHg$U7#L3sgP@qVcF7|sAC@_o1@L8T%nhlAuXbb>+w zr-MPpqPqd7Vo)JNv|><Dzy?U1Kn_E}R56B;foNl}g*DNdL75(1@dc=NV2KPAHXtE$ zP;i47=vZ6om`>Z@Ne625SN{C7&B!76|9RFemkJ#Opc>E(g7w1C%>nWAUMle(U|?WK z_^Wyjv^ikG%I6R5kX;BH&cjFyp!y8f7R8VR<y=0fb1)=9DdjlGas~zl3`tPc2rB+S z@)(k!@&eXB#*hS6rm%4$3`tNe3(n@)>;zS%P{%UB0uQ7C<c2LE0vkU4e^*;*x3xpl zm)3xjMMrj+K^1}ON)QuN(t>E1Q@{;PP@o})E=Ykbhya~J2Bl#XBLi$G31$SS_yx;? z+5@n)X&92AOb0sF7NinG5>z6B5+O(uGcUnBjVXgO>_E011DOUICPkxPLHS^>!@58u z2ef&c+h_M>4o>Zy^4IEC)hz;5m>`3dpeBJTQ4pU2)S3YAi7>>-&3Ho+T0Jsg`kEbT z1uRhz%$i_#G=zb26azy;v;&yWVB&xt=b%sn$zjBg658xFND(Msf@qj4KrJp1A0`fB zqu`rR-Wn(kPdESnC%D3#0;8d77+}GO;iU8b|Nlo<3>&Y*Pz-7ryn`AEb1y7h-$KPP zD46>&+{?hA-~?(1fplP#bcVUh7#dLrK`N2!To500_zQ@JxdX%oVMYen`1Jx17dj^e zVs?NC5bgvKXi);P>g@mj|6ySORRX6hK?;y^!&j&bEI7dJGngWnASA^wFyJio!G<{W zL)5`&hDcOCLL8FvV0?#u2p>~DOdLYP)WP&2)WhT<_Ax}l_^33ddWbwjqyuPJ7UTz5 z@pu#(udo1M0JUFXieQ2hpo);D2SH{aumxIJgNiqhEG!)`z>*e79mp_H;Q<>AfGL8h z0T)w;K-w7?7+_@=tQdzEDa;_F7#J8Zbb~a)(j!ss0=Wg`CQ!Kr^8H|O7sxFjH-Tzf zP}mF>cY)jjauYNH7zT^GKye6i6Uc3#a2qV{0wqXL8Uw{ADD3FquA?A3vE?3E?GMW! zAaywV86Zc)M!Ya;7*H<?Ht&U1QW6vw3=9nDh5AyEogfUGmBZPl0a*bxg!uNLOial0 zOLn%7t7mr9AKIE!4DtlXHdr$S)Y}H}89-Ge#>PI_NIgcea~7<J0bcw-xeTBo4iFo& zQfmYWGcYh<R+tWR+!}C7CcJVxk4y4en2miLR1(v|Gf){=sZFqz#O3i@zNCAD13G;g zY7mCYC48s5*W;4p(>1aOU0nc@M|T_p!(Nau*3e)$;6Psc4r(HTs&wFhCKvP|z}fZs zd5Cw7!6A<WGka9tFw9dqa6pUMK~y}(;W^Y)*vdRu_0t6vXXu79kTViU2sVR(ktIN} zAq#aLh9szHz?ls|I-weg&ju=IvJU6;d-+X2Rbtw)#%v;bHh}f*7(n>}+fG#mlC#2E zkpHno@vEsuw&X?egRRhpjwggZwCezRfP?1YK^9|#DQKWn7aDG`)()%}4ND*3b_q-o zOc2^uV!+wuZ0-wN6v=wrVdux2Go=slO3gjva<`tP-LrA?&gZU$f1dp9j$IZn(&4dN zx`*Kj!=A_|XKG8$TiRWxWV*RXOp<)6h~_HTs6WgB44@herU)ho>q_Eu)zbFQS67Dw zxwlPKTdJlLBB>hjE9>#PiJsloci(hGm|T^6k|)0HSG3#i_#Nx|*Zw)VJ9g%rjH$M+ z{i%Me@_h1Tzb4k-^En^xyYH0f!Z@XmS|>oE%D_N;lH>dNvNQ8lwa?<K{}<l4U-Sz! z!vQh_BW6Iu*T~Tb>hgfZKot=&L)xIqy)>^VH8BTdJOijR4?PS*-#4+KSl>0Tq^J@s z1tJpVAPe<C=>fzaFpTVFkRw2;fC)q}5P4Ayx&a_Va9~6a0-Bm59d0L-_Wx3w<^anJ zFdC`=Y!IlZ0Wm<$6wrhLh=%b&G|06e3@Z+ktFpIz&aQB3_<h2L`Ka_PkQx$P2~v&& z!(0cWak&ySoq^4j$j0)AJFI=j{m#8z^W3w|Y7=0U1XM`_a{nE=(gq~fU=Le%0Ly|f zdn7<X0M(5_A$uQ`pg{^Sasa5Q3R|m!Aqg61-3Zc#ZHx?*_CYNdkUWM?P_*EzMnJ~G z91imlY@i8ep%QZY$I^!B?M{=`EYx%?QXimKBQOIPK=FjU^By@EKyJmy2i1NI3{^)U z_{1Rwh6dQEIY=u50|O{NpiD5;upbf^$a>&xCx|&!E({DOklC;<CA<v>n&tw{6o4@5 zz#oczC}{%W53qe8JD}#m^nhtt`wr|{kbjWe3)KVH4|1am0|VT>FgDa&M4OXB_ad1K zb|chnAPOVAVd0CU2jo5w28Ss~{0KCBVQgBs7i0(2T$mfdG$?#Q802_R`apIsR1e6l zpfCoz7nZg_VGUzL&81rSg3JZQEmGqb6wV+FbtagC@X^u(vb#WRSeU}tDCWY_Acg4x z<X&i4fgJ`8M{IcwB#Y!;s2)(*g2EV-UqLho!`V<ZAf40+Uz{VgpeYVmfIzHcU?8ut z$zTF$WHP8gX@tvR2E!J;VU)a}*(jW)Jt*vOHvK{K<~Yl2kg+6}+2J35=kd;Rby#yu z((*!1L^gVv4XOyh9s)TS^;i><+x)N%6+~AkY-yS?*7m8c+okHhAK+TeOJ-Do-H#v~ z>M@4)(JjI`Rsrh4<BT29>IIy!1JX%y>=gBHFS*61>ECF%_v`vvTTk@Zfz5R@fD#7m z%oqleBgP9FI7o#NScH+>%mLPoAPzK<-$#aRJ;caGpmiZQLmMPXa%gW`aQgCbxf>oE z=eX|R)7jjL9@?Pz1$zqA27w&KgkG57bS-H03Mhku^rHte0|QQffV7e9kC|*vlFJRI zJMPu0cpT5MR}|eJuqGjR?FGtlLL{dgSaTSbrKvN`g|qwy%|fFGIVeP7`&}^-31~48 zY#$M3uq!}=7B<`m+j;?>;SLUQ4DodKbq)52H#RY_Ff_L?Gc_}GGBGlBv@|s`cD6Jz zH8F5?G_|yJi8nU2Of)dEv@kJGwJ<R^Hb_b|H8e9fvrI8aGqf}@G6$bc2s(*7-Zb7c z-pJ6@EZ)!}&BDMU**H1P+{h%=G||%1B+b-3CDk<9!Z<nEBq`p^!ob+j!p+#k($vYt z$;H*l)x_D*(8<`+*~P@t+}YIt1`MGL7!BouC<_B)H)I;bM#jb_CPoIvU<egvxDE<W zq?s^KHvuGM0u3whgbM@1|No3o0Z?NeqyVN676)L3poLiIX#_Su2NMTrM!`RzJoNE2 z*v?LdW~c(#3U7=7SW~D1ypyV+33-q@%ya=uV$`W`7#{5BgoYI?o4~rx_-76o6rdeh z1pOT3U<L*T^q?U))ChF|R67cVGxLB}%@Ln@<YC2(G!p{@Qs!~Aa5FS8wJ>#YH8VG{ zv~+c}G&FWHGc|H?HgU8xHFb?QGO{o>Hga-wH83(Vad9!SG;uXDHgd8scd;<GG_i0C zEKN))$^@Um8<d&?x%nqP%t*y3)ga#3+{MM%$;?^BD8<FZ(L}{4#l+CrK*cD<$=S_J z#VEzt$kElvz{t|o%)~t2+21cXB*@Xz&($R!n%tq31(b$Ruv`P-85qF$AllW)#M#l( z($d_?!o}Fa*wNC$#Kg$b$kNov+|<;_z!9d$0G1nJG)w}<htV)`7>y=w0uzVPX!0Oo zH)t*gu|XIYALM?JJQ$mTNdpsCGdD9=GZ4=iB4P}oP<#y)f>I_ZZon)<pvny5eS!^q z{er8Yz#u+2+$V~GsB#0eSQB@32`f2Z*$KA%8YYgCyg?k;Ru=SZ0~<_bXalKYU|_&m zqI`xbfNjcvSq&SL!?GC!qJsyT^I*j!tVn_xzyQiNFhwxIB@n#~yim<hE`rL1GBHX% zE2s|GE-iE)!**vd^gvC3m325xgl$74*+iJhFd8<L2J<AW5X3p(0(Bun%k;Fr|Nk39 z3quA5GE37+r~wF??9vqEGMtSRY|DXYrx>=i0aopT`i~&zF&Ho~FyQQ}fJV`AHabB% zp~;B&0sYGJ?~*-M#d)thxw>V8-P#?XWDRl$tZfBb<pDk)1N|sSlG~lsshJ<NV)O*{ zpdQBvPS6r>@Xh8(ZKJ)QjsViE2Y8hbOc5-ZcR&@L1ce4R4BIdc(*VmCI2#AaT#XBD zu1!8Lo12v}N6*1wV%G8kEz?{F*oIYfg9v6YbXTQ91u*7x85pXZVcS-5H=9O1H0)w% z=f~F4w|Dy-QZ4hJJL#4kcqFrbTby7m8A-19MSYU6)B*P8-~aJhWWxu~a3?tj88;dv zIcN&Upy-f?@OTKZq@CnEgy9pYz^I3y0f9l0mE?wT48huIpn!s}_+VgQ0L`+4#4rnd z*j8eU$`Z5(3O1>ZAqm<XwF_h*Qcd~^G&PG{lY**Ym?Btxwil{sH&inQWdPEJZBYs9 z$^~}d@d#{^3=T4G(NME6{Rmnx0FuO%fi@?xEJ61LX+WJMgo=nlU5LKUtq&^C&<|y> zK^4OM-Uu4u1)Z7#mB*k&pc*iixau%6FxWsPu~g^|4%eV&!K~^5tteq&V7Lku$Dp*K zrlI#O;2TCkR)TbCK^4MGh7A$HOMQ?c6bx#;vM?}cKs91<?*fPWP#st#8SEe8lys1B z+lEt;p~2w^Zb=3PA>0mPum?@EgEV7v5Q8*6oxecZu%<}{1_sz@BvxagafD^TAVY)w zC8)9J5i|)Z&Ts|FFoDwO3Y(zf44_sohz)DKqvrxf1{;txmbA{u5QamBfx!x=j2})J z&~{ajB)SV27+~kHVakAdV%YUKgM_iTnt{OurwnL?DM%92o*IxaQt3r>I*09bCpm+t zKvNaT8lRHuRAF*$garo4PK6yrMZ8APq;$nX=K19M@h`a=|B$N@+BbxEvtfZnu!MwF z*0-THV<{vW98A&T3{<*;)Z^R=3p!Td7Dxs5GHHS1c07_!=b(}pRS>A^h3%+8FKQM; zH8H@(ypBKx&=tbYg=3fqRRC&afS8#1(G4VwHFvw>lz|-!foU4F)q$m+_r_rwBLnPg zGfdN9r}Cl8FoO3}gA7EMVPNn931jgOBLipyKS&Z&4`@Xmb{WtjUhFcUeVo{3-hhOW zN;ufK<0Ggz1_hf4#B`VkR4t|qD>S)crXL1|1~sT8Y#s`hmcgbS29wy9&oeaG8$oqq z$s!C4u+xaJNH*B7#%C-n2g2w(P{pv~N)I|+`~WJBL8(IBh3Q>J1_s#ivgi%P6)<B~ zLK)Z;f(#}~A!v|}D21Rkh(sv_MGH|1K@Aw96oQIKq7;IfVHgTW8@HfJaYQw4FGF+2 zXyX<d5D03taf=8GFbh;%u`n<UfyQma4aj+>BdKw_6&y!cw(WxIt&31e^cr$5RGa~J z(6SV$I>fd47qlW2qyfD(!pHzR6A7CP0|V>?ZFD^h43;1bSQ=^!44@lBL6Yct7#ToE zU|^GBV1R8xLD$2;07(iA7)??}hIo)sSY3d-5owM?558tBXbTQV8@k&V8OUkijy5kr zVF@aXKs2bvwudz<VKj9758hJ@gf=hlL3LnI|DYo1`C}$joB_N62YTohNDONeI1eO) zHS@4AFo5p;1Ic410(EGf!(!$Ed(eq<*tO~7(suTYk1cFo6x~CUL1uyQ6cE9{zyLb| z8jIx&_MjD&Aa$5-UJnw+*6}@i=8Wx6s3f}O3!&l+i=YfUD2-{p7}Rs<Mofq5V3+}A zXhIcYbPO)AGcXuJC9!$VVFT0z3`vj|HbEuP?Vk!2XP5?MY=+VprhvpjD{DbCrvG+; zgt3Jm14Dt68PwV6md}Q2Vt^g1x(6zN;d#(lX$4dgi_049@8Xs`V1EO*q=^$~St&>! z-A@b*uR+4t{lq{<Nyo_W5^5lZ_dw!Y&_KeJ<X~VJ?a6@3#lhB-X|TsLOy6J+>g9rB z7HfhfI7~m<lL3Vt*4E5uPX-z^FbdRo7#ckp@IHDL28NN;lYwkL$2vgy!SNF`4zU&z zu~13Ox(RgbBS;cmhLHhuq$_qAPmnOy3<WwC79@#o8e(5t6-XL;UHHqT8n>i}(=(_f zM!g2=$H5x7(4Dj3&A}k`u$~!g{Q&rISdav4B`t`J3qvbXcxxH9^%&>g<%HllJwFSK zeV0!=cz?l?-;5xafeeQ&UxY0KU;wS;1fRGXoLW+nnU`LSd2k)fM<D$No3-Xm|F*P2 g&-%zkkeRSP9Y_v@%kEhOvYgtl30iXr;)B!!05*+{QUCw| diff --git a/Source/RWTHVRToolkit/Private/Pawn/ContinuousMovementComponent.cpp b/Source/RWTHVRToolkit/Private/Pawn/ContinuousMovementComponent.cpp index c931c7c2..4f7db1bc 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/ContinuousMovementComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/ContinuousMovementComponent.cpp @@ -3,166 +3,22 @@ #include "Pawn/ContinuousMovementComponent.h" -#include "DrawDebugHelpers.h" #include "EnhancedInputComponent.h" #include "EnhancedInputSubsystems.h" -#include "Camera/CameraComponent.h" -#include "Components/CapsuleComponent.h" #include "Engine/LocalPlayer.h" #include "GameFramework/PlayerController.h" #include "Pawn/VRPawnInputConfig.h" #include "Utility/VirtualRealityUtilities.h" -UContinuousMovementComponent::UContinuousMovementComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) -{ - CapsuleColliderComponent = CreateDefaultSubobject<UCapsuleComponent>(TEXT("CapsuleCollider")); - CapsuleColliderComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); - CapsuleColliderComponent->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Overlap); - CapsuleColliderComponent->SetCollisionResponseToChannel(ECollisionChannel::ECC_WorldStatic, ECollisionResponse::ECR_Block); - CapsuleColliderComponent->SetCapsuleSize(CapsuleRadius, 80.0f); - - VRPawn = Cast<AVirtualRealityPawn>(GetOwner()); -} - -void UContinuousMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction){ - - SetCapsuleColliderToUserSize(); - - FVector PositionChange = GetPendingInputVector(); - - if (NavigationMode == EVRNavigationModes::NAV_WALK) - { - PositionChange.Z = 0.0f; - ConsumeInputVector(); - AddInputVector(PositionChange); - } - - if(NavigationMode == EVRNavigationModes::NAV_FLY || NavigationMode == EVRNavigationModes::NAV_WALK) - { - MoveByGravityOrStepUp(DeltaTime); - CheckForPhysWalkingCollision(); - - if(CheckForVirtualMovCollision(PositionChange, DeltaTime)) - { - ConsumeInputVector(); - } - } - - if(NavigationMode == EVRNavigationModes::NAV_NONE) - { - ConsumeInputVector(); - } - - Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - - LastHeadPosition = HeadComponent->GetComponentLocation(); -} - void UContinuousMovementComponent::BeginPlay() { Super::BeginPlay(); - - SetUpdatedComponent(VRPawn->GetRootComponent()); - SetHeadComponent(VRPawn->CapsuleRotationFix); + VRPawn = Cast<AVirtualRealityPawn>(GetOwner()); SetupInputActions(); } -bool UContinuousMovementComponent::CheckForVirtualMovCollision(FVector PositionChange, float DeltaTime) -{ - FVector ProbePosition = PositionChange.GetSafeNormal() * GetMaxSpeed() * DeltaTime; - FHitResult FHitResultVR; - CapsuleColliderComponent->AddWorldOffset(ProbePosition, true, &FHitResultVR); - if (FVector::Distance(FHitResultVR.Location, CapsuleColliderComponent->GetComponentLocation()) < CapsuleColliderComponent->GetScaledCapsuleRadius()) - { - return true; - } - return false; -} - -void UContinuousMovementComponent::SetHeadComponent(USceneComponent* NewHeadComponent) -{ - HeadComponent = NewHeadComponent; - CapsuleColliderComponent->SetupAttachment(HeadComponent); - const float HalfHeight = 80.0f; //this is just an initial value to look good in editor - CapsuleColliderComponent->SetCapsuleSize(CapsuleRadius, HalfHeight); - CapsuleColliderComponent->SetWorldLocation(FVector(0.0f, 0.0f,HalfHeight)); -} - -void UContinuousMovementComponent::SetCapsuleColliderToUserSize() -{ - float CharachterSize = abs(UpdatedComponent->GetComponentLocation().Z - HeadComponent->GetComponentLocation().Z); - - if (CharachterSize > MaxStepHeight) - { - float ColliderHeight = CharachterSize - MaxStepHeight; - float ColliderHalfHeight = ColliderHeight / 2.0f; - if (ColliderHalfHeight <= CapsuleRadius) - {//Make the collider to a Sphere - CapsuleColliderComponent->SetCapsuleSize(ColliderHalfHeight, ColliderHalfHeight); - } - else - {//Make the collider to a Capsule - CapsuleColliderComponent->SetCapsuleSize(CapsuleRadius, ColliderHalfHeight); - } - - CapsuleColliderComponent->SetWorldLocation(HeadComponent->GetComponentLocation()); - CapsuleColliderComponent->AddWorldOffset(FVector(0, 0, -ColliderHalfHeight)); - CapsuleColliderComponent->SetWorldRotation(FRotator(0, 0, 1)); - } - else - { - CapsuleColliderComponent->SetWorldLocation(HeadComponent->GetComponentLocation()); - CapsuleColliderComponent->SetWorldRotation(FRotator(0, 0, 1)); - } -} - -void UContinuousMovementComponent::CheckForPhysWalkingCollision() -{ - FVector CurrentHeadPosition = HeadComponent->GetComponentLocation(); - FVector Direction = CurrentHeadPosition - LastHeadPosition; - FHitResult FHitResultPhys; - CapsuleColliderComponent->AddWorldOffset(Direction, true, &FHitResultPhys); - - if (FHitResultPhys.bBlockingHit) - { - UpdatedComponent->AddLocalOffset(FHitResultPhys.Normal*FHitResultPhys.PenetrationDepth); - } -} - -void UContinuousMovementComponent::MoveByGravityOrStepUp(float DeltaSeconds) -{ - FVector StartLineTraceUnderCollider = CapsuleColliderComponent->GetComponentLocation(); - StartLineTraceUnderCollider.Z -= CapsuleColliderComponent->GetScaledCapsuleHalfHeight(); - FHitResult HitDetailsMultiLineTrace = CreateMultiLineTrace(FVector(0, 0, -1), StartLineTraceUnderCollider, CapsuleColliderComponent->GetScaledCapsuleRadius() / 4.0f, false); - float DistanceDifference = abs(MaxStepHeight - HitDetailsMultiLineTrace.Distance); - //Going up (in Fly and Walk Mode) - if ((HitDetailsMultiLineTrace.bBlockingHit && HitDetailsMultiLineTrace.Distance < MaxStepHeight)) - { - ShiftVertically(DistanceDifference, UpSteppingAcceleration, DeltaSeconds, 1); - } - //Gravity (only in Walk Mode) - else if (NavigationMode==EVRNavigationModes::NAV_WALK && ((HitDetailsMultiLineTrace.bBlockingHit && HitDetailsMultiLineTrace.Distance > MaxStepHeight) || (HitDetailsMultiLineTrace.GetActor() == nullptr && HitDetailsMultiLineTrace.Distance != -1.0f))) - { - ShiftVertically(DistanceDifference, GravityAcceleration, DeltaSeconds, -1); - } -} - -void UContinuousMovementComponent::ShiftVertically(float DiffernceDistance, float VerticalAcceleration, float DeltaSeconds, int Direction) -{ - VerticalSpeed += VerticalAcceleration * DeltaSeconds; - if (VerticalSpeed*DeltaSeconds < DiffernceDistance) - { - UpdatedComponent->AddLocalOffset(FVector(0.f, 0.f, Direction * VerticalSpeed * DeltaSeconds)); - } - else - { - UpdatedComponent->AddLocalOffset(FVector(0.f, 0.f, Direction * DiffernceDistance)); - VerticalSpeed = 0; - } -} - void UContinuousMovementComponent::SetupInputActions() { // simple way of changing the handedness @@ -216,69 +72,18 @@ void UContinuousMovementComponent::SetupInputActions() APlayerController* PC = Cast<APlayerController>(VRPawn->GetController()); if (PC) { + UE_LOG(LogTemp,Error,TEXT("PC PLAYER CONtroller is valid")); PC->bShowMouseCursor = true; PC->bEnableClickEvents = true; PC->bEnableMouseOverEvents = true; } EI->BindAction(InputActions->DesktopRotation, ETriggerEvent::Started, this, &UContinuousMovementComponent::StartDesktopRotation); EI->BindAction(InputActions->DesktopRotation, ETriggerEvent::Completed, this, &UContinuousMovementComponent::EndDesktopRotation); - } -} - - -FHitResult UContinuousMovementComponent::CreateLineTrace(FVector Direction, const FVector Start, bool Visibility) -{ - //Re-initialize hit info - FHitResult HitDetails = FHitResult(ForceInit); - - FVector End = ((Direction * 1000.f) + Start); - // additional trace parameters - FCollisionQueryParams TraceParams(FName(TEXT("InteractTrace")), true, NULL); - TraceParams.bTraceComplex = true; //to use complex collision on whatever we interact with to provide better precision. - TraceParams.bReturnPhysicalMaterial = true; //to provide details about the physical material, if one exists on the thing we hit, to come back in our hit result. - - if (Visibility) - DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 1, 0, 1); - - if (GetWorld()->LineTraceSingleByChannel(HitDetails, Start, End, ECC_Visibility, TraceParams)) - { - if (HitDetails.bBlockingHit) - { - } + EI->BindAction(InputActions->MoveUp, ETriggerEvent::Triggered,this,&UContinuousMovementComponent::OnBeginUp); } - return HitDetails; } -FHitResult UContinuousMovementComponent::CreateMultiLineTrace(FVector Direction, const FVector Start, float Radius, bool Visibility) -{ - TArray<FVector> StartVectors; - TArray<FHitResult> OutHits; - FHitResult HitDetailsMultiLineTrace; - HitDetailsMultiLineTrace.Distance = -1.0f;//(Distance=-1) not existing, but to know if this Variable not Initialized(when all Traces not compatible) - - StartVectors.Add(Start); //LineTraceCenter - StartVectors.Add(Start + FVector(0, -Radius, 0)); //LineTraceLeft - StartVectors.Add(Start + FVector(0, +Radius, 0)); //LineTraceRight - StartVectors.Add(Start + FVector(+Radius, 0, 0)); //LineTraceFront - StartVectors.Add(Start + FVector(-Radius, 0, 0)); //LineTraceBehind - - bool IsBlockingHitAndSameActor = true; - bool IsAllNothingHiting = true; - // loop through TArray - for (FVector& Vector : StartVectors) - { - FHitResult OutHit = CreateLineTrace(Direction, Vector, Visibility); - OutHits.Add(OutHit); - IsBlockingHitAndSameActor &= (OutHit.GetActor() == OutHits[0].GetActor()); //If all Hiting the same Object, then you are (going up/down) or (walking) - IsAllNothingHiting &= (OutHit.GetActor() == nullptr); //If all Hiting nothing, then you are falling - } - - if (IsBlockingHitAndSameActor || IsAllNothingHiting) - HitDetailsMultiLineTrace = OutHits[0]; - - return HitDetailsMultiLineTrace; -} void UContinuousMovementComponent::StartDesktopRotation() { @@ -292,13 +97,15 @@ void UContinuousMovementComponent::EndDesktopRotation() void UContinuousMovementComponent::OnBeginMove(const FInputActionValue& Value) { - const FVector ForwardDir = UVirtualRealityUtilities::IsDesktopMode() ? VRPawn->Head->GetForwardVector() : MovementHand->GetForwardVector(); - const FVector RightDir = UVirtualRealityUtilities::IsDesktopMode() ? VRPawn->Head->GetRightVector() : MovementHand->GetRightVector(); + + const bool bGazeDirected = UVirtualRealityUtilities::IsDesktopMode() || SteeringMode == EVRSteeringModes::STEER_GAZE_DIRECTED; + + const FVector ForwardDir = bGazeDirected ? VRPawn->Head->GetForwardVector() : MovementHand->GetForwardVector(); + const FVector RightDir = bGazeDirected ? VRPawn->Head->GetRightVector() : MovementHand->GetRightVector(); if (VRPawn->Controller != nullptr) { const FVector2D MoveValue = Value.Get<FVector2D>(); - const FRotator MovementRotation(0, VRPawn->Controller->GetControlRotation().Yaw, 0); // Forward/Backward direction if (MoveValue.X != 0.f) @@ -363,7 +170,7 @@ void UContinuousMovementComponent::SetCameraOffset() const void UContinuousMovementComponent::UpdateRightHandForDesktopInteraction() { - APlayerController* PC = Cast<APlayerController>(GetController()); + APlayerController* PC = Cast<APlayerController>(VRPawn->GetController()); if (PC) { FVector MouseLocation, MouseDirection; @@ -373,21 +180,11 @@ void UContinuousMovementComponent::UpdateRightHandForDesktopInteraction() } } -/*void UContinuousMovementComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) +void UContinuousMovementComponent::OnBeginUp(const FInputActionValue& Value) { - Super::PostEditChangeProperty(PropertyChangedEvent); + const float MoveValue = Value.Get<FVector2D>().X; + UE_LOG(LogTemp,Warning,TEXT("MoveUp: %f"),MoveValue); + //the right hand is rotated on desktop to follow the cursor so it's forward is also changing with cursor position + VRPawn->AddMovementInput(VRPawn->Head->GetUpVector(), MoveValue); - FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None; - - if (PropertyName == GET_MEMBER_NAME_CHECKED(AVirtualRealityPawn, bMoveWithRightHand) || - PropertyName == GET_MEMBER_NAME_CHECKED(AVirtualRealityPawn, bSnapTurn)) - { - // if we want to change input bindings, we need to setup the player input again to load a different mapping context, - // or assign a different function to an input action. - // This is automatically done by restarting the pawn(calling SetupPlayerInputComponent() directly results in crashes) - // only do this in the editor - #if WITH_EDITOR - VRPawn->Restart(); -#endif - } -}*/ \ No newline at end of file +} \ No newline at end of file diff --git a/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp b/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp new file mode 100644 index 00000000..4b32da47 --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp @@ -0,0 +1,193 @@ + +#include "Pawn/VRPawnMovement.h" +#include "DrawDebugHelpers.h" + +UVRPawnMovement::UVRPawnMovement(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) +{ + CapsuleColliderComponent = CreateDefaultSubobject<UCapsuleComponent>(TEXT("CapsuleCollider")); + CapsuleColliderComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); + CapsuleColliderComponent->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Overlap); + CapsuleColliderComponent->SetCollisionResponseToChannel(ECollisionChannel::ECC_WorldStatic, ECollisionResponse::ECR_Block); + CapsuleColliderComponent->SetCapsuleSize(CapsuleRadius, 80.0f); +} + +void UVRPawnMovement::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction){ + + SetCapsuleColliderToUserSize(); + + FVector PositionChange = GetPendingInputVector(); + + if (NavigationMode == EVRNavigationModes::NAV_WALK) + { + PositionChange.Z = 0.0f; + ConsumeInputVector(); + AddInputVector(PositionChange); + } + + if(NavigationMode == EVRNavigationModes::NAV_FLY || NavigationMode == EVRNavigationModes::NAV_WALK) + { + MoveByGravityOrStepUp(DeltaTime); + CheckForPhysWalkingCollision(); + + if(CheckForVirtualMovCollision(PositionChange, DeltaTime)) + { + ConsumeInputVector(); + } + } + + if(NavigationMode == EVRNavigationModes::NAV_NONE) + { + ConsumeInputVector(); + } + + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + LastHeadPosition = HeadComponent->GetComponentLocation(); +} + +bool UVRPawnMovement::CheckForVirtualMovCollision(FVector PositionChange, float DeltaTime) +{ + FVector ProbePosition = PositionChange.GetSafeNormal() * GetMaxSpeed() * DeltaTime; + FHitResult FHitResultVR; + CapsuleColliderComponent->AddWorldOffset(ProbePosition, true, &FHitResultVR); + if (FVector::Distance(FHitResultVR.Location, CapsuleColliderComponent->GetComponentLocation()) < CapsuleColliderComponent->GetScaledCapsuleRadius()) + { + return true; + } + return false; +} + +void UVRPawnMovement::SetHeadComponent(USceneComponent* NewHeadComponent) +{ + HeadComponent = NewHeadComponent; + CapsuleColliderComponent->SetupAttachment(HeadComponent); + const float HalfHeight = 80.0f; //this is just an initial value to look good in editor + CapsuleColliderComponent->SetCapsuleSize(CapsuleRadius, HalfHeight); + CapsuleColliderComponent->SetWorldLocation(FVector(0.0f, 0.0f,HalfHeight)); +} + +void UVRPawnMovement::SetCapsuleColliderToUserSize() +{ + float CharachterSize = abs(UpdatedComponent->GetComponentLocation().Z - HeadComponent->GetComponentLocation().Z); + + if (CharachterSize > MaxStepHeight) + { + float ColliderHeight = CharachterSize - MaxStepHeight; + float ColliderHalfHeight = ColliderHeight / 2.0f; + if (ColliderHalfHeight <= CapsuleRadius) + {//Make the collider to a Sphere + CapsuleColliderComponent->SetCapsuleSize(ColliderHalfHeight, ColliderHalfHeight); + } + else + {//Make the collider to a Capsule + CapsuleColliderComponent->SetCapsuleSize(CapsuleRadius, ColliderHalfHeight); + } + + CapsuleColliderComponent->SetWorldLocation(HeadComponent->GetComponentLocation()); + CapsuleColliderComponent->AddWorldOffset(FVector(0, 0, -ColliderHalfHeight)); + CapsuleColliderComponent->SetWorldRotation(FRotator(0, 0, 1)); + } + else + { + CapsuleColliderComponent->SetWorldLocation(HeadComponent->GetComponentLocation()); + CapsuleColliderComponent->SetWorldRotation(FRotator(0, 0, 1)); + } +} + +void UVRPawnMovement::CheckForPhysWalkingCollision() +{ + FVector CurrentHeadPosition = HeadComponent->GetComponentLocation(); + FVector Direction = CurrentHeadPosition - LastHeadPosition; + FHitResult FHitResultPhys; + CapsuleColliderComponent->AddWorldOffset(Direction, true, &FHitResultPhys); + + if (FHitResultPhys.bBlockingHit) + { + UpdatedComponent->AddLocalOffset(FHitResultPhys.Normal*FHitResultPhys.PenetrationDepth); + } +} + +void UVRPawnMovement::MoveByGravityOrStepUp(float DeltaSeconds) +{ + FVector StartLineTraceUnderCollider = CapsuleColliderComponent->GetComponentLocation(); + StartLineTraceUnderCollider.Z -= CapsuleColliderComponent->GetScaledCapsuleHalfHeight(); + FHitResult HitDetailsMultiLineTrace = CreateMultiLineTrace(FVector(0, 0, -1), StartLineTraceUnderCollider, CapsuleColliderComponent->GetScaledCapsuleRadius() / 4.0f, false); + float DistanceDifference = abs(MaxStepHeight - HitDetailsMultiLineTrace.Distance); + //Going up (in Fly and Walk Mode) + if ((HitDetailsMultiLineTrace.bBlockingHit && HitDetailsMultiLineTrace.Distance < MaxStepHeight)) + { + ShiftVertically(DistanceDifference, UpSteppingAcceleration, DeltaSeconds, 1); + } + //Gravity (only in Walk Mode) + else if (NavigationMode==EVRNavigationModes::NAV_WALK && ((HitDetailsMultiLineTrace.bBlockingHit && HitDetailsMultiLineTrace.Distance > MaxStepHeight) || (HitDetailsMultiLineTrace.GetActor() == nullptr && HitDetailsMultiLineTrace.Distance != -1.0f))) + { + ShiftVertically(DistanceDifference, GravityAcceleration, DeltaSeconds, -1); + } +} + +void UVRPawnMovement::ShiftVertically(float DiffernceDistance, float VerticalAcceleration, float DeltaSeconds, int Direction) +{ + VerticalSpeed += VerticalAcceleration * DeltaSeconds; + if (VerticalSpeed*DeltaSeconds < DiffernceDistance) + { + UpdatedComponent->AddLocalOffset(FVector(0.f, 0.f, Direction * VerticalSpeed * DeltaSeconds)); + } + else + { + UpdatedComponent->AddLocalOffset(FVector(0.f, 0.f, Direction * DiffernceDistance)); + VerticalSpeed = 0; + } +} + +FHitResult UVRPawnMovement::CreateLineTrace(FVector Direction, const FVector Start, bool Visibility) +{ + //Re-initialize hit info + FHitResult HitDetails = FHitResult(ForceInit); + + FVector End = ((Direction * 1000.f) + Start); + // additional trace parameters + FCollisionQueryParams TraceParams(FName(TEXT("InteractTrace")), true, NULL); + TraceParams.bTraceComplex = true; //to use complex collision on whatever we interact with to provide better precision. + TraceParams.bReturnPhysicalMaterial = true; //to provide details about the physical material, if one exists on the thing we hit, to come back in our hit result. + + if (Visibility) + DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 1, 0, 1); + + if (GetWorld()->LineTraceSingleByChannel(HitDetails, Start, End, ECC_Visibility, TraceParams)) + { + if (HitDetails.bBlockingHit) + { + } + } + return HitDetails; +} + +FHitResult UVRPawnMovement::CreateMultiLineTrace(FVector Direction, const FVector Start, float Radius, bool Visibility) +{ + TArray<FVector> StartVectors; + TArray<FHitResult> OutHits; + FHitResult HitDetailsMultiLineTrace; + HitDetailsMultiLineTrace.Distance = -1.0f;//(Distance=-1) not existing, but to know if this Variable not Initialized(when all Traces not compatible) + + StartVectors.Add(Start); //LineTraceCenter + StartVectors.Add(Start + FVector(0, -Radius, 0)); //LineTraceLeft + StartVectors.Add(Start + FVector(0, +Radius, 0)); //LineTraceRight + StartVectors.Add(Start + FVector(+Radius, 0, 0)); //LineTraceFront + StartVectors.Add(Start + FVector(-Radius, 0, 0)); //LineTraceBehind + + bool IsBlockingHitAndSameActor = true; + bool IsAllNothingHiting = true; + // loop through TArray + for (FVector& Vector : StartVectors) + { + FHitResult OutHit = CreateLineTrace(Direction, Vector, Visibility); + OutHits.Add(OutHit); + IsBlockingHitAndSameActor &= (OutHit.GetActor() == OutHits[0].GetActor()); //If all Hiting the same Object, then you are (going up/down) or (walking) + IsAllNothingHiting &= (OutHit.GetActor() == nullptr); //If all Hiting nothing, then you are falling + } + + if (IsBlockingHitAndSameActor || IsAllNothingHiting) + HitDetailsMultiLineTrace = OutHits[0]; + + return HitDetailsMultiLineTrace; +} \ No newline at end of file diff --git a/Source/RWTHVRToolkit/Private/Pawn/VirtualRealityPawn.cpp b/Source/RWTHVRToolkit/Private/Pawn/VirtualRealityPawn.cpp index 3676a790..a0afeac4 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/VirtualRealityPawn.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/VirtualRealityPawn.cpp @@ -11,6 +11,7 @@ #include "EnhancedInputSubsystems.h" #include "Camera/CameraComponent.h" #include "Pawn/VRPawnInputConfig.h" +#include "Pawn/VRPawnMovement.h" AVirtualRealityPawn::AVirtualRealityPawn(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -34,10 +35,10 @@ AVirtualRealityPawn::AVirtualRealityPawn(const FObjectInitializer& ObjectInitial CapsuleRotationFix = CreateDefaultSubobject<USceneComponent>(TEXT("CapsuleRotationFix")); CapsuleRotationFix->SetUsingAbsoluteRotation(true); CapsuleRotationFix->SetupAttachment(Head); - - /*PawnMovement = CreateDefaultSubobject<UVRPawnMovement>(TEXT("Pawn Movement")); + + PawnMovement = CreateDefaultSubobject<UVRPawnMovement>(TEXT("Pawn Movement")); PawnMovement->SetUpdatedComponent(RootComponent); - PawnMovement->SetHeadComponent(CapsuleRotationFix);*/ + PawnMovement->SetHeadComponent(CapsuleRotationFix); RightHand = CreateDefaultSubobject<UUniversalTrackedComponent>(TEXT("Right Hand")); RightHand->ProxyType = ETrackedComponentType::TCT_RIGHT_HAND; @@ -59,20 +60,6 @@ AVirtualRealityPawn::AVirtualRealityPawn(const FObjectInitializer& ObjectInitial void AVirtualRealityPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { - - // simple way of changing the handedness - /*if(bMoveWithRightHand) - { - MovementHand = RightHand; - RotationHand = LeftHand; - IMCMovement = IMCMovementRight; - } else - { - MovementHand = LeftHand; - RotationHand = RightHand; - IMCMovement = IMCMovementLeft; - }*/ - const APlayerController* PlayerController = Cast<APlayerController>(GetController()); UEnhancedInputLocalPlayerSubsystem* InputSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()); if(!InputSubsystem) @@ -83,7 +70,6 @@ void AVirtualRealityPawn::SetupPlayerInputComponent(UInputComponent* PlayerInput InputSubsystem->ClearAllMappings(); // add Input Mapping context - //InputSubsystem->AddMappingContext(IMCMovement,0); InputSubsystem->AddMappingContext(IMCBase,0); UEnhancedInputComponent* EI = Cast<UEnhancedInputComponent>(PlayerInputComponent); @@ -95,101 +81,7 @@ void AVirtualRealityPawn::SetupPlayerInputComponent(UInputComponent* PlayerInput // grabbing EI->BindAction(InputActions->Grab, ETriggerEvent::Started, this, &AVirtualRealityPawn::OnBeginGrab); EI->BindAction(InputActions->Grab, ETriggerEvent::Completed, this, &AVirtualRealityPawn::OnEndGrab); - - /*// walking - EI->BindAction(InputActions->Move, ETriggerEvent::Triggered, this, &AVirtualRealityPawn::OnBeginMove);*/ - - /* - // turning - if(bSnapTurn && !UVirtualRealityUtilities::IsDesktopMode()) - { - EI->BindAction(InputActions->Turn, ETriggerEvent::Started, this, &AVirtualRealityPawn::OnBeginSnapTurn); - } else - { - EI->BindAction(InputActions->Turn, ETriggerEvent::Triggered, this, &AVirtualRealityPawn::OnBeginTurn); - } - */ - - // bind functions for desktop rotations only on holding down right mouse - if (UVirtualRealityUtilities::IsDesktopMode()) - { - APlayerController* PC = Cast<APlayerController>(GetController()); - if (PC) - { - PC->bShowMouseCursor = true; - PC->bEnableClickEvents = true; - PC->bEnableMouseOverEvents = true; - } - /*EI->BindAction(InputActions->DesktopRotation, ETriggerEvent::Started, this, &AVirtualRealityPawn::StartDesktopRotation); - EI->BindAction(InputActions->DesktopRotation, ETriggerEvent::Completed, this, &AVirtualRealityPawn::EndDesktopRotation);*/ - } -} - -/*void AVirtualRealityPawn::StartDesktopRotation() -{ - bApplyDesktopRotation = true; -} - -void AVirtualRealityPawn::EndDesktopRotation() -{ - bApplyDesktopRotation = false; -}*/ - -/*void AVirtualRealityPawn::SetCameraOffset() const -{ - // this also incorporates the BaseEyeHeight, if set as static offset, - // rotations are still around the center of the pawn (on the floor), so pitch rotations look weird - FVector Location; - FRotator Rotation; - GetActorEyesViewPoint(Location, Rotation); - CameraComponent->SetWorldLocationAndRotation(Location, Rotation); -}*/ - -/*void AVirtualRealityPawn::UpdateRightHandForDesktopInteraction() -{ - APlayerController* PC = Cast<APlayerController>(GetController()); - if (PC) - { - FVector MouseLocation, MouseDirection; - PC->DeprojectMousePositionToWorld(MouseLocation, MouseDirection); - FRotator HandOrientation = MouseDirection.ToOrientationRotator(); - RightHand->SetWorldRotation(HandOrientation); - } -}*/ - -/*void AVirtualRealityPawn::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) -{ - Super::PostEditChangeProperty(PropertyChangedEvent); - FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None; - - if (PropertyName == GET_MEMBER_NAME_CHECKED(AVirtualRealityPawn, bMoveWithRightHand) || - PropertyName == GET_MEMBER_NAME_CHECKED(AVirtualRealityPawn, bSnapTurn)) - { - // if we want to change input bindings, we need to setup the player input again to load a different mapping context, - // or assign a different function to an input action. - // This is automatically done by restarting the pawn(calling SetupPlayerInputComponent() directly results in crashes) - // only do this in the editor - #if WITH_EDITOR - Restart(); - #endif - } -}*/ - - -void AVirtualRealityPawn::OnUp(const FInputActionValue& Value) -{ - const float MoveValue = Value.Get<FVector2D>().X; - UE_LOG(LogTemp,Warning,TEXT("MoveUp: %f"),MoveValue); - //the right hand is rotated on desktop to follow the cursor so it's forward is also changing with cursor position - if (RightHand && !UVirtualRealityUtilities::IsDesktopMode()) - { - AddMovementInput(RightHand->GetUpVector(), MoveValue); - } - else if (Head) - { - AddMovementInput(Head->GetUpVector(), MoveValue); - } } // legacy grabbing @@ -216,65 +108,4 @@ void AVirtualRealityPawn::OnEndGrab(const FInputActionValue& Value) UE_LOG(LogTemp,Warning,TEXT("EndGrab")); } -/*void AVirtualRealityPawn::OnBeginMove(const FInputActionValue& Value) -{ - const FVector ForwardDir = UVirtualRealityUtilities::IsDesktopMode() ? Head->GetForwardVector() : MovementHand->GetForwardVector(); - const FVector RightDir = UVirtualRealityUtilities::IsDesktopMode() ? Head->GetRightVector() : MovementHand->GetRightVector(); - - if (Controller != nullptr) - { - const FVector2D MoveValue = Value.Get<FVector2D>(); - const FRotator MovementRotation(0, Controller->GetControlRotation().Yaw, 0); - - // Forward/Backward direction - if (MoveValue.X != 0.f) - { - AddMovementInput(ForwardDir, MoveValue.X); - } - - // Right/Left direction - if (MoveValue.Y != 0.f) - { - AddMovementInput(RightDir, MoveValue.Y); - } - } -}*/ - -/*void AVirtualRealityPawn::OnBeginTurn(const FInputActionValue& Value) -{ - if(UVirtualRealityUtilities::IsDesktopMode() && !bApplyDesktopRotation) return; - if (Controller != nullptr) - { - const FVector2D TurnValue = Value.Get<FVector2D>(); - - if (TurnValue.X != 0.f) - { - AddControllerYawInput(TurnRateFactor * TurnValue.X); - if (UVirtualRealityUtilities::IsDesktopMode()) - { - UpdateRightHandForDesktopInteraction(); - } - } - - if (TurnValue.Y != 0.f) - { - if (UVirtualRealityUtilities::IsDesktopMode() && bApplyDesktopRotation) - { - AddControllerPitchInput(TurnRateFactor * TurnValue.Y); - SetCameraOffset(); - } - } - } -} - -void AVirtualRealityPawn::OnBeginSnapTurn(const FInputActionValue& Value) -{ - const FVector2D TurnValue = Value.Get<FVector2D>(); - - if (TurnValue.X != 0.f) - { - AddControllerYawInput(SnapTurnAngle); - } -}*/ - diff --git a/Source/RWTHVRToolkit/Public/Pawn/ContinuousMovementComponent.h b/Source/RWTHVRToolkit/Public/Pawn/ContinuousMovementComponent.h index fb335133..0b068288 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/ContinuousMovementComponent.h +++ b/Source/RWTHVRToolkit/Public/Pawn/ContinuousMovementComponent.h @@ -3,68 +3,54 @@ #pragma once #include "CoreMinimal.h" -#include "GameFramework/FloatingPawnMovement.h" -#include "Components/CapsuleComponent.h" #include "Pawn/VirtualRealityPawn.h" - +#include "Components/ActorComponent.h" #include "ContinuousMovementComponent.generated.h" -/* - * This Movement component is needed since in VR not only the pawn itself (UpdatedComponent) is moved but also the - * user herself can walk and thereby move the CameraComponent, which can also lead to collisions or e.g. going up steps - * - * The four modes are: - * None: No controller movement is applied and no corrections regarding steps or collisions with walls are done - * Ghost: The same as above but now the Inputs can be used for unconstrained flying (also through objects) - * Fly: The user can fly but not through walls etc. When the user walks against a wall the scene is moved with her to avoid walking through - * The user can also walk up stairs with a maximum step height of MaxStepHeight - * Walk: Additionally to Fly now gravity keeps the user on the floor - */ - UENUM(BlueprintType) -enum class EVRNavigationModes : uint8 +enum class EVRSteeringModes : uint8 { - NAV_NONE UMETA(DisplayName = "None (no controller movement)"), - NAV_GHOST UMETA(DisplayName = "Ghost (flying, also through walls)"), - NAV_FLY UMETA(DisplayName = "Fly (prohibiting collisions)"), - NAV_WALK UMETA(DisplayName = "Walk (gravity and prohibiting collisions)") + STEER_GAZE_DIRECTED UMETA(DisplayName = "Gaze Directed (Movement input is applied in head component direction)"), + STEER_HAND_DIRECTED UMETA(DisplayName = "Hand Direced (Movement input is applied in controller direction)") }; - /** * */ UCLASS(Blueprintable) -class RWTHVRTOOLKIT_API UContinuousMovementComponent : public UFloatingPawnMovement +class RWTHVRTOOLKIT_API UContinuousMovementComponent : public UActorComponent { GENERATED_BODY() public: - UContinuousMovementComponent(const FObjectInitializer& ObjectInitializer); - - virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, - FActorComponentTickFunction* ThisTickFunction) override; - virtual void BeginPlay() override; - void SetHeadComponent(USceneComponent* NewHeadComponent); - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") - EVRNavigationModes NavigationMode = EVRNavigationModes::NAV_WALK; - + EVRSteeringModes SteeringMode = EVRSteeringModes::STEER_HAND_DIRECTED; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") - float MaxStepHeight = 40.0f; + bool bMoveWithRightHand = false; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") - float GravityAcceleration = 981.0f; + bool bSnapTurn = false; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") - float UpSteppingAcceleration = 500.0f; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement", meta=(EditCondition="!bSnapTurn")) + float TurnRateFactor = 1.0f; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") - float CapsuleRadius = 40.0f; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement", meta=(EditCondition="bSnapTurn",ClampMin=0,ClampMax=360)) + float SnapTurnAngle = 22.5; + + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input") + class UInputMappingContext* IMCMovementRight; + + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input") + class UInputMappingContext* IMCMovementLeft; + + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input") + class UVRPawnInputConfig* InputActions; + /*Movement Input*/ @@ -77,14 +63,8 @@ public: UFUNCTION(BlueprintCallable) void OnBeginSnapTurn(const FInputActionValue& Value); - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input") - class UInputMappingContext* IMCMovementRight; - - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input") - class UInputMappingContext* IMCMovementLeft; - - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "VR Movement|Input") - class UVRPawnInputConfig* InputActions; + UFUNCTION(BlueprintCallable) + void OnBeginUp(const FInputActionValue& Value); /*Desktop Testing*/ // the idea is that you have to hold the right mouse button to do rotations @@ -95,36 +75,10 @@ public: void EndDesktopRotation(); bool bApplyDesktopRotation = false; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") - bool bMoveWithRightHand = false; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") - bool bSnapTurn = false; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement", meta=(EditCondition="!bSnapTurn")) - float TurnRateFactor = 1.0f; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement", meta=(EditCondition="bSnapTurn",ClampMin=0,ClampMax=360)) - float SnapTurnAngle = 22.5; private: - FHitResult CreateLineTrace(FVector Direction, const FVector Start, bool Visibility); - FHitResult CreateMultiLineTrace(FVector Direction, const FVector Start, float Radius, bool Visibility); - void SetCapsuleColliderToUserSize(); - void CheckForPhysWalkingCollision(); - bool CheckForVirtualMovCollision(FVector PositionChange, float DeltaTime); - void MoveByGravityOrStepUp(float DeltaSeconds); - void ShiftVertically(float DiffernceDistance, float VerticalAcceleration, float DeltaSeconds, int Direction); - //(direction = Down = -1), (direction = Up = 1) - - UPROPERTY(VisibleAnywhere) UCapsuleComponent* CapsuleColliderComponent = nullptr; - UPROPERTY() USceneComponent* HeadComponent = nullptr; - - float VerticalSpeed = 0.0f; - FVector LastHeadPosition; - - + + UPROPERTY() UUniversalTrackedComponent* MovementHand; @@ -136,10 +90,9 @@ private: void SetupInputActions(); + UPROPERTY() AVirtualRealityPawn* VRPawn; - /*virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;*/ - /** * Fixes camera rotation in desktop mode. */ diff --git a/Source/RWTHVRToolkit/Public/Pawn/VRPawnMovement.h b/Source/RWTHVRToolkit/Public/Pawn/VRPawnMovement.h new file mode 100644 index 00000000..298799e5 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Pawn/VRPawnMovement.h @@ -0,0 +1,73 @@ +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/FloatingPawnMovement.h" +#include "Components/CapsuleComponent.h" +#include "Camera/CameraComponent.h" + +#include "VRPawnMovement.generated.h" + +/* + * This Movement component is needed since in VR not only the pawn itself (UpdatedComponent) is moved but also the + * user herself can walk and thereby move the CameraComponent, which can also lead to collisions or e.g. going up steps + * + * The four modes are: + * None: No controller movement is applied and no corrections regarding steps or collisions with walls are done + * Ghost: The same as above but now the Inputs can be used for unconstrained flying (also through objects) + * Fly: The user can fly but not through walls etc. When the user walks against a wall the scene is moved with her to avoid walking through + * The user can also walk up stairs with a maximum step height of MaxStepHeight + * Walk: Additionally to Fly now gravity keeps the user on the floor + */ + +UENUM(BlueprintType) +enum class EVRNavigationModes : uint8 +{ + NAV_NONE UMETA(DisplayName = "None (no controller movement)"), + NAV_GHOST UMETA(DisplayName = "Ghost (flying, also through walls)"), + NAV_FLY UMETA(DisplayName = "Fly (prohibiting collisions)"), + NAV_WALK UMETA(DisplayName = "Walk (gravity and prohibiting collisions)") +}; + +UCLASS() +class RWTHVRTOOLKIT_API UVRPawnMovement : public UFloatingPawnMovement +{ + GENERATED_UCLASS_BODY() + +public: + + virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) override; + + void SetHeadComponent(USceneComponent* NewHeadComponent); + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") + EVRNavigationModes NavigationMode = EVRNavigationModes::NAV_WALK; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") + float MaxStepHeight = 40.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") + float GravityAcceleration = 981.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") + float UpSteppingAcceleration = 500.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR Movement") + float CapsuleRadius = 40.0f; + +private: + FHitResult CreateLineTrace(FVector Direction, const FVector Start, bool Visibility); + FHitResult CreateMultiLineTrace(FVector Direction, const FVector Start, float Radius, bool Visibility); + void SetCapsuleColliderToUserSize(); + void CheckForPhysWalkingCollision(); + bool CheckForVirtualMovCollision(FVector PositionChange, float DeltaTime); + void MoveByGravityOrStepUp(float DeltaSeconds); + void ShiftVertically(float DiffernceDistance, float VerticalAcceleration, float DeltaSeconds, int Direction); + //(direction = Down = -1), (direction = Up = 1) + + UPROPERTY(VisibleAnywhere) UCapsuleComponent* CapsuleColliderComponent = nullptr; + UPROPERTY() USceneComponent* HeadComponent = nullptr; + + float VerticalSpeed = 0.0f; + FVector LastHeadPosition; +}; diff --git a/Source/RWTHVRToolkit/Public/Pawn/VirtualRealityPawn.h b/Source/RWTHVRToolkit/Public/Pawn/VirtualRealityPawn.h index 79f7af9b..ecca5440 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/VirtualRealityPawn.h +++ b/Source/RWTHVRToolkit/Public/Pawn/VirtualRealityPawn.h @@ -5,6 +5,7 @@ #include "BasicVRInteractionComponent.h" #include "CoreMinimal.h" #include "UniversalTrackedComponent.h" +#include "Pawn/VRPawnMovement.h" #include "VirtualRealityPawn.generated.h" class UCameraComponent; @@ -32,22 +33,7 @@ public: /* Interaction */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn|Interaction") UBasicVRInteractionComponent* BasicVRInteraction; - - /* Movement */ - /*UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Movement") - UVRPawnMovement* PawnMovement;*/ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn|Movement") - bool bMoveWithRightHand = false; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn|Movement") - bool bSnapTurn = false; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn|Movement", meta=(EditCondition="!bSnapTurn")) - float TurnRateFactor = 1.0f; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn|Movement", meta=(EditCondition="bSnapTurn",ClampMin=0,ClampMax=360)) - float SnapTurnAngle = 22.5; /** Workaround dummy component to prevent the Capsule from rotating in the editor, if LiveLink tracking is being used. * This happens due to the rotation of the Capsule being set only while in Play Mode (instead of using e.g. absolute rotation). @@ -58,7 +44,9 @@ public: */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn|Movement") USceneComponent* CapsuleRotationFix; - + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn|Movement") + UVRPawnMovement* PawnMovement; /* CameraComponent */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn|Camera") @@ -68,10 +56,6 @@ public: protected: virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override; - /* Movement */ - UFUNCTION(BlueprintCallable, Category = "Pawn|Movement") - void OnUp(const FInputActionValue& Value); - /* Interaction */ UFUNCTION(BlueprintCallable, Category = "Pawn|Interaction") void OnBeginFire(const FInputActionValue& Value); @@ -84,17 +68,6 @@ protected: UFUNCTION(BlueprintCallable, Category = "Pawn|Interaction") void OnEndGrab(const FInputActionValue& Value); - - /* - UFUNCTION(BlueprintCallable, Category = "Pawn|Interaction") - void OnBeginMove(const FInputActionValue& Value); - - UFUNCTION(BlueprintCallable, Category = "Pawn|Interaction") - void OnBeginTurn(const FInputActionValue& Value); - - UFUNCTION(BlueprintCallable, Category = "Pawn|Interaction") - void OnBeginSnapTurn(const FInputActionValue& Value); - */ /* Input */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pawn|Input") @@ -102,33 +75,5 @@ protected: UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pawn|Input") class UVRPawnInputConfig* InputActions; - - /*Desktop Testing*/ - // the idea is that you have to hold the right mouse button to do rotations - /*UFUNCTION() - void StartDesktopRotation(); - - UFUNCTION() - void EndDesktopRotation(); - - bool bApplyDesktopRotation = false;*/ - - /** - * Fixes camera rotation in desktop mode. - */ - /*void SetCameraOffset() const; - void UpdateRightHandForDesktopInteraction();*/ - -private: - /*UPROPERTY() - UUniversalTrackedComponent* MovementHand; - - UPROPERTY() - UUniversalTrackedComponent* RotationHand; - - UPROPERTY() - class UInputMappingContext* IMCMovement;*/ - - /*virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;*/ }; -- GitLab