.katex { display: block; text-align: center; white-space: nowrap; }
.katex-display > .katex > .katex-html { display: block; }
.katex-display > .katex > .katex-html > .tag { position: absolute; right: 0px; }
.katex { font: 1.21em/1.2 KaTeX_Main, "Times New Roman", serif; text-indent: 0px; text-rendering: auto; }
.katex * { }
.katex .katex-mathml { position: absolute; clip: rect(1px, 1px, 1px, 1px); padding: 0px; border: 0px; height: 1px; width: 1px; overflow: hidden; }
.katex .katex-html { }
.katex .katex-html > .newline { display: block; }
.katex .base { position: relative; display: inline-block; white-space: nowrap; width: min-content; }
.katex .strut { display: inline-block; }
.katex .textbf { font-weight: bold; }
.katex .textit { font-style: italic; }
.katex .textrm { font-family: KaTeX_Main; }
.katex .textsf { font-family: KaTeX_SansSerif; }
.katex .texttt { font-family: KaTeX_Typewriter; }
.katex .mathit { font-family: KaTeX_Math; font-style: italic; }
.katex .mathrm { font-style: normal; }
.katex .mathbf { font-family: KaTeX_Main; font-weight: bold; }
.katex .boldsymbol { font-family: KaTeX_Math; font-weight: bold; font-style: italic; }
.katex .amsrm { font-family: KaTeX_AMS; }
.katex .mathbb, .katex .textbb { font-family: KaTeX_AMS; }
.katex .mathcal { font-family: KaTeX_Caligraphic; }
.katex .mathfrak, .katex .textfrak { font-family: KaTeX_Fraktur; }
.katex .mathtt { font-family: KaTeX_Typewriter; }
.katex .mathscr, .katex .textscr { font-family: KaTeX_Script; }
.katex .mathsf, .katex .textsf { font-family: KaTeX_SansSerif; }
.katex .mainit { font-family: KaTeX_Main; font-style: italic; }
.katex .mainrm { font-family: KaTeX_Main; font-style: normal; }
.katex .vlist-t { display: inline-table; table-layout: fixed; }
.katex .vlist-r { display: table-row; }
.katex .vlist { display: table-cell; vertical-align: bottom; position: relative; }
.katex .vlist > span { display: block; height: 0px; position: relative; }
.katex .vlist > span > span { display: inline-block; }
.katex .vlist > span > .pstrut { overflow: hidden; width: 0px; }
.katex .vlist-t2 { margin-right: -2px; }
.katex .vlist-s { display: table-cell; vertical-align: bottom; font-size: 1px; width: 2px; min-width: 2px; }
.katex .msupsub { text-align: left; }
.katex .mfrac > span > span { text-align: center; }
.katex .mfrac .frac-line { display: inline-block; width: 100%; border-bottom-style: solid; }
.katex .mspace { display: inline-block; }
.katex .llap, .katex .rlap, .katex .clap { width: 0px; position: relative; }
.katex .llap > .inner, .katex .rlap > .inner, .katex .clap > .inner { position: absolute; }
.katex .llap > .fix, .katex .rlap > .fix, .katex .clap > .fix { display: inline-block; }
.katex .llap > .inner { right: 0px; }
.katex .rlap > .inner, .katex .clap > .inner { left: 0px; }
.katex .clap > .inner > span { margin-left: -50%; margin-right: 50%; }
.katex .rule { display: inline-block; border: 0px solid; position: relative; }
.katex .overline .overline-line, .katex .underline .underline-line, .katex .hline { display: inline-block; width: 100%; border-bottom-style: solid; }
.katex .hdashline { display: inline-block; width: 100%; border-bottom-style: dashed; }
.katex .sqrt > .root { margin-left: 0.277778em; margin-right: -0.555556em; }
.katex .sizing, .katex .fontsize-ensurer { display: inline-block; }
.katex .sizing.reset-size1.size1, .katex .fontsize-ensurer.reset-size1.size1 { font-size: 1em; }
.katex .sizing.reset-size1.size2, .katex .fontsize-ensurer.reset-size1.size2 { font-size: 1.2em; }
.katex .sizing.reset-size1.size3, .katex .fontsize-ensurer.reset-size1.size3 { font-size: 1.4em; }
.katex .sizing.reset-size1.size4, .katex .fontsize-ensurer.reset-size1.size4 { font-size: 1.6em; }
.katex .sizing.reset-size1.size5, .katex .fontsize-ensurer.reset-size1.size5 { font-size: 1.8em; }
.katex .sizing.reset-size1.size6, .katex .fontsize-ensurer.reset-size1.size6 { font-size: 2em; }
.katex .sizing.reset-size1.size7, .katex .fontsize-ensurer.reset-size1.size7 { font-size: 2.4em; }
.katex .sizing.reset-size1.size8, .katex .fontsize-ensurer.reset-size1.size8 { font-size: 2.88em; }
.katex .sizing.reset-size1.size9, .katex .fontsize-ensurer.reset-size1.size9 { font-size: 3.456em; }
.katex .sizing.reset-size1.size10, .katex .fontsize-ensurer.reset-size1.size10 { font-size: 4.148em; }
.katex .sizing.reset-size1.size11, .katex .fontsize-ensurer.reset-size1.size11 { font-size: 4.976em; }
.katex .sizing.reset-size2.size1, .katex .fontsize-ensurer.reset-size2.size1 { font-size: 0.833333em; }
.katex .sizing.reset-size2.size2, .katex .fontsize-ensurer.reset-size2.size2 { font-size: 1em; }
.katex .sizing.reset-size2.size3, .katex .fontsize-ensurer.reset-size2.size3 { font-size: 1.16667em; }
.katex .sizing.reset-size2.size4, .katex .fontsize-ensurer.reset-size2.size4 { font-size: 1.33333em; }
.katex .sizing.reset-size2.size5, .katex .fontsize-ensurer.reset-size2.size5 { font-size: 1.5em; }
.katex .sizing.reset-size2.size6, .katex .fontsize-ensurer.reset-size2.size6 { font-size: 1.66667em; }
.katex .sizing.reset-size2.size7, .katex .fontsize-ensurer.reset-size2.size7 { font-size: 2em; }
.katex .sizing.reset-size2.size8, .katex .fontsize-ensurer.reset-size2.size8 { font-size: 2.4em; }
.katex .sizing.reset-size2.size9, .katex .fontsize-ensurer.reset-size2.size9 { font-size: 2.88em; }
.katex .sizing.reset-size2.size10, .katex .fontsize-ensurer.reset-size2.size10 { font-size: 3.45667em; }
.katex .sizing.reset-size2.size11, .katex .fontsize-ensurer.reset-size2.size11 { font-size: 4.14667em; }
.katex .sizing.reset-size3.size1, .katex .fontsize-ensurer.reset-size3.size1 { font-size: 0.714286em; }
.katex .sizing.reset-size3.size2, .katex .fontsize-ensurer.reset-size3.size2 { font-size: 0.857143em; }
.katex .sizing.reset-size3.size3, .katex .fontsize-ensurer.reset-size3.size3 { font-size: 1em; }
.katex .sizing.reset-size3.size4, .katex .fontsize-ensurer.reset-size3.size4 { font-size: 1.14286em; }
.katex .sizing.reset-size3.size5, .katex .fontsize-ensurer.reset-size3.size5 { font-size: 1.28571em; }
.katex .sizing.reset-size3.size6, .katex .fontsize-ensurer.reset-size3.size6 { font-size: 1.42857em; }
.katex .sizing.reset-size3.size7, .katex .fontsize-ensurer.reset-size3.size7 { font-size: 1.71429em; }
.katex .sizing.reset-size3.size8, .katex .fontsize-ensurer.reset-size3.size8 { font-size: 2.05714em; }
.katex .sizing.reset-size3.size9, .katex .fontsize-ensurer.reset-size3.size9 { font-size: 2.46857em; }
.katex .sizing.reset-size3.size10, .katex .fontsize-ensurer.reset-size3.size10 { font-size: 2.96286em; }
.katex .sizing.reset-size3.size11, .katex .fontsize-ensurer.reset-size3.size11 { font-size: 3.55429em; }
.katex .sizing.reset-size4.size1, .katex .fontsize-ensurer.reset-size4.size1 { font-size: 0.625em; }
.katex .sizing.reset-size4.size2, .katex .fontsize-ensurer.reset-size4.size2 { font-size: 0.75em; }
.katex .sizing.reset-size4.size3, .katex .fontsize-ensurer.reset-size4.size3 { font-size: 0.875em; }
.katex .sizing.reset-size4.size4, .katex .fontsize-ensurer.reset-size4.size4 { font-size: 1em; }
.katex .sizing.reset-size4.size5, .katex .fontsize-ensurer.reset-size4.size5 { font-size: 1.125em; }
.katex .sizing.reset-size4.size6, .katex .fontsize-ensurer.reset-size4.size6 { font-size: 1.25em; }
.katex .sizing.reset-size4.size7, .katex .fontsize-ensurer.reset-size4.size7 { font-size: 1.5em; }
.katex .sizing.reset-size4.size8, .katex .fontsize-ensurer.reset-size4.size8 { font-size: 1.8em; }
.katex .sizing.reset-size4.size9, .katex .fontsize-ensurer.reset-size4.size9 { font-size: 2.16em; }
.katex .sizing.reset-size4.size10, .katex .fontsize-ensurer.reset-size4.size10 { font-size: 2.5925em; }
.katex .sizing.reset-size4.size11, .katex .fontsize-ensurer.reset-size4.size11 { font-size: 3.11em; }
.katex .sizing.reset-size5.size1, .katex .fontsize-ensurer.reset-size5.size1 { font-size: 0.555556em; }
.katex .sizing.reset-size5.size2, .katex .fontsize-ensurer.reset-size5.size2 { font-size: 0.666667em; }
.katex .sizing.reset-size5.size3, .katex .fontsize-ensurer.reset-size5.size3 { font-size: 0.777778em; }
.katex .sizing.reset-size5.size4, .katex .fontsize-ensurer.reset-size5.size4 { font-size: 0.888889em; }
.katex .sizing.reset-size5.size5, .katex .fontsize-ensurer.reset-size5.size5 { font-size: 1em; }
.katex .sizing.reset-size5.size6, .katex .fontsize-ensurer.reset-size5.size6 { font-size: 1.11111em; }
.katex .sizing.reset-size5.size7, .katex .fontsize-ensurer.reset-size5.size7 { font-size: 1.33333em; }
.katex .sizing.reset-size5.size8, .katex .fontsize-ensurer.reset-size5.size8 { font-size: 1.6em; }
.katex .sizing.reset-size5.size9, .katex .fontsize-ensurer.reset-size5.size9 { font-size: 1.92em; }
.katex .sizing.reset-size5.size10, .katex .fontsize-ensurer.reset-size5.size10 { font-size: 2.30444em; }
.katex .sizing.reset-size5.size11, .katex .fontsize-ensurer.reset-size5.size11 { font-size: 2.76444em; }
.katex .sizing.reset-size6.size1, .katex .fontsize-ensurer.reset-size6.size1 { font-size: 0.5em; }
.katex .sizing.reset-size6.size2, .katex .fontsize-ensurer.reset-size6.size2 { font-size: 0.6em; }
.katex .sizing.reset-size6.size3, .katex .fontsize-ensurer.reset-size6.size3 { font-size: 0.7em; }
.katex .sizing.reset-size6.size4, .katex .fontsize-ensurer.reset-size6.size4 { font-size: 0.8em; }
.katex .sizing.reset-size6.size5, .katex .fontsize-ensurer.reset-size6.size5 { font-size: 0.9em; }
.katex .sizing.reset-size6.size6, .katex .fontsize-ensurer.reset-size6.size6 { font-size: 1em; }
.katex .sizing.reset-size6.size7, .katex .fontsize-ensurer.reset-size6.size7 { font-size: 1.2em; }
.katex .sizing.reset-size6.size8, .katex .fontsize-ensurer.reset-size6.size8 { font-size: 1.44em; }
.katex .sizing.reset-size6.size9, .katex .fontsize-ensurer.reset-size6.size9 { font-size: 1.728em; }
.katex .sizing.reset-size6.size10, .katex .fontsize-ensurer.reset-size6.size10 { font-size: 2.074em; }
.katex .sizing.reset-size6.size11, .katex .fontsize-ensurer.reset-size6.size11 { font-size: 2.488em; }
.katex .sizing.reset-size7.size1, .katex .fontsize-ensurer.reset-size7.size1 { font-size: 0.416667em; }
.katex .sizing.reset-size7.size2, .katex .fontsize-ensurer.reset-size7.size2 { font-size: 0.5em; }
.katex .sizing.reset-size7.size3, .katex .fontsize-ensurer.reset-size7.size3 { font-size: 0.583333em; }
.katex .sizing.reset-size7.size4, .katex .fontsize-ensurer.reset-size7.size4 { font-size: 0.666667em; }
.katex .sizing.reset-size7.size5, .katex .fontsize-ensurer.reset-size7.size5 { font-size: 0.75em; }
.katex .sizing.reset-size7.size6, .katex .fontsize-ensurer.reset-size7.size6 { font-size: 0.833333em; }
.katex .sizing.reset-size7.size7, .katex .fontsize-ensurer.reset-size7.size7 { font-size: 1em; }
.katex .sizing.reset-size7.size8, .katex .fontsize-ensurer.reset-size7.size8 { font-size: 1.2em; }
.katex .sizing.reset-size7.size9, .katex .fontsize-ensurer.reset-size7.size9 { font-size: 1.44em; }
.katex .sizing.reset-size7.size10, .katex .fontsize-ensurer.reset-size7.size10 { font-size: 1.72833em; }
.katex .sizing.reset-size7.size11, .katex .fontsize-ensurer.reset-size7.size11 { font-size: 2.07333em; }
.katex .sizing.reset-size8.size1, .katex .fontsize-ensurer.reset-size8.size1 { font-size: 0.347222em; }
.katex .sizing.reset-size8.size2, .katex .fontsize-ensurer.reset-size8.size2 { font-size: 0.416667em; }
.katex .sizing.reset-size8.size3, .katex .fontsize-ensurer.reset-size8.size3 { font-size: 0.486111em; }
.katex .sizing.reset-size8.size4, .katex .fontsize-ensurer.reset-size8.size4 { font-size: 0.555556em; }
.katex .sizing.reset-size8.size5, .katex .fontsize-ensurer.reset-size8.size5 { font-size: 0.625em; }
.katex .sizing.reset-size8.size6, .katex .fontsize-ensurer.reset-size8.size6 { font-size: 0.694444em; }
.katex .sizing.reset-size8.size7, .katex .fontsize-ensurer.reset-size8.size7 { font-size: 0.833333em; }
.katex .sizing.reset-size8.size8, .katex .fontsize-ensurer.reset-size8.size8 { font-size: 1em; }
.katex .sizing.reset-size8.size9, .katex .fontsize-ensurer.reset-size8.size9 { font-size: 1.2em; }
.katex .sizing.reset-size8.size10, .katex .fontsize-ensurer.reset-size8.size10 { font-size: 1.44028em; }
.katex .sizing.reset-size8.size11, .katex .fontsize-ensurer.reset-size8.size11 { font-size: 1.72778em; }
.katex .sizing.reset-size9.size1, .katex .fontsize-ensurer.reset-size9.size1 { font-size: 0.289352em; }
.katex .sizing.reset-size9.size2, .katex .fontsize-ensurer.reset-size9.size2 { font-size: 0.347222em; }
.katex .sizing.reset-size9.size3, .katex .fontsize-ensurer.reset-size9.size3 { font-size: 0.405093em; }
.katex .sizing.reset-size9.size4, .katex .fontsize-ensurer.reset-size9.size4 { font-size: 0.462963em; }
.katex .sizing.reset-size9.size5, .katex .fontsize-ensurer.reset-size9.size5 { font-size: 0.520833em; }
.katex .sizing.reset-size9.size6, .katex .fontsize-ensurer.reset-size9.size6 { font-size: 0.578704em; }
.katex .sizing.reset-size9.size7, .katex .fontsize-ensurer.reset-size9.size7 { font-size: 0.694444em; }
.katex .sizing.reset-size9.size8, .katex .fontsize-ensurer.reset-size9.size8 { font-size: 0.833333em; }
.katex .sizing.reset-size9.size9, .katex .fontsize-ensurer.reset-size9.size9 { font-size: 1em; }
.katex .sizing.reset-size9.size10, .katex .fontsize-ensurer.reset-size9.size10 { font-size: 1.20023em; }
.katex .sizing.reset-size9.size11, .katex .fontsize-ensurer.reset-size9.size11 { font-size: 1.43981em; }
.katex .sizing.reset-size10.size1, .katex .fontsize-ensurer.reset-size10.size1 { font-size: 0.24108em; }
.katex .sizing.reset-size10.size2, .katex .fontsize-ensurer.reset-size10.size2 { font-size: 0.289296em; }
.katex .sizing.reset-size10.size3, .katex .fontsize-ensurer.reset-size10.size3 { font-size: 0.337512em; }
.katex .sizing.reset-size10.size4, .katex .fontsize-ensurer.reset-size10.size4 { font-size: 0.385728em; }
.katex .sizing.reset-size10.size5, .katex .fontsize-ensurer.reset-size10.size5 { font-size: 0.433944em; }
.katex .sizing.reset-size10.size6, .katex .fontsize-ensurer.reset-size10.size6 { font-size: 0.48216em; }
.katex .sizing.reset-size10.size7, .katex .fontsize-ensurer.reset-size10.size7 { font-size: 0.578592em; }
.katex .sizing.reset-size10.size8, .katex .fontsize-ensurer.reset-size10.size8 { font-size: 0.694311em; }
.katex .sizing.reset-size10.size9, .katex .fontsize-ensurer.reset-size10.size9 { font-size: 0.833173em; }
.katex .sizing.reset-size10.size10, .katex .fontsize-ensurer.reset-size10.size10 { font-size: 1em; }
.katex .sizing.reset-size10.size11, .katex .fontsize-ensurer.reset-size10.size11 { font-size: 1.19961em; }
.katex .sizing.reset-size11.size1, .katex .fontsize-ensurer.reset-size11.size1 { font-size: 0.200965em; }
.katex .sizing.reset-size11.size2, .katex .fontsize-ensurer.reset-size11.size2 { font-size: 0.241158em; }
.katex .sizing.reset-size11.size3, .katex .fontsize-ensurer.reset-size11.size3 { font-size: 0.28135em; }
.katex .sizing.reset-size11.size4, .katex .fontsize-ensurer.reset-size11.size4 { font-size: 0.321543em; }
.katex .sizing.reset-size11.size5, .katex .fontsize-ensurer.reset-size11.size5 { font-size: 0.361736em; }
.katex .sizing.reset-size11.size6, .katex .fontsize-ensurer.reset-size11.size6 { font-size: 0.401929em; }
.katex .sizing.reset-size11.size7, .katex .fontsize-ensurer.reset-size11.size7 { font-size: 0.482315em; }
.katex .sizing.reset-size11.size8, .katex .fontsize-ensurer.reset-size11.size8 { font-size: 0.578778em; }
.katex .sizing.reset-size11.size9, .katex .fontsize-ensurer.reset-size11.size9 { font-size: 0.694534em; }
.katex .sizing.reset-size11.size10, .katex .fontsize-ensurer.reset-size11.size10 { font-size: 0.833601em; }
.katex .sizing.reset-size11.size11, .katex .fontsize-ensurer.reset-size11.size11 { font-size: 1em; }
.katex .delimsizing.size1 { font-family: KaTeX_Size1; }
.katex .delimsizing.size2 { font-family: KaTeX_Size2; }
.katex .delimsizing.size3 { font-family: KaTeX_Size3; }
.katex .delimsizing.size4 { font-family: KaTeX_Size4; }
.katex .delimsizing.mult .delim-size1 > span { font-family: KaTeX_Size1; }
.katex .delimsizing.mult .delim-size4 > span { font-family: KaTeX_Size4; }
.katex .nulldelimiter { display: inline-block; width: 0.12em; }
.katex .delimcenter { position: relative; }
.katex .op-symbol { position: relative; }
.katex .op-symbol.small-op { font-family: KaTeX_Size1; }
.katex .op-symbol.large-op { font-family: KaTeX_Size2; }
.katex .op-limits > .vlist-t { text-align: center; }
.katex .accent > .vlist-t { text-align: center; }
.katex .accent .accent-body:not(.accent-full) { width: 0px; }
.katex .accent .accent-body { position: relative; }
.katex .overlay { display: block; }
.katex .mtable .vertical-separator { display: inline-block; margin: 0px -0.025em; border-right: 0.05em solid; }
.katex .mtable .vs-dashed { border-right: 0.05em dashed; }
.katex .mtable .arraycolsep { display: inline-block; }
.katex .mtable .col-align-c > .vlist-t { text-align: center; }
.katex .mtable .col-align-l > .vlist-t { text-align: left; }
.katex .mtable .col-align-r > .vlist-t { text-align: right; }
.katex .svg-align { text-align: left; }
.katex svg, .screenShotTempCanvas { display: block; position: absolute; width: 100%; height: inherit; fill: currentcolor; stroke: currentcolor; fill-rule: nonzero; fill-opacity: 1; stroke-width: 1; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0; stroke-opacity: 1; }
.katex svg path { stroke: none; }
.katex .stretchy { width: 100%; display: block; position: relative; overflow: hidden; }
.katex .stretchy::before, .katex .stretchy::after { content: ""; }
.katex .hide-tail { width: 100%; position: relative; overflow: hidden; }
.katex .halfarrow-left { position: absolute; left: 0px; width: 50.2%; overflow: hidden; }
.katex .halfarrow-right { position: absolute; right: 0px; width: 50.2%; overflow: hidden; }
.katex .brace-left { position: absolute; left: 0px; width: 25.1%; overflow: hidden; }
.katex .brace-center { position: absolute; left: 25%; width: 50%; overflow: hidden; }
.katex .brace-right { position: absolute; right: 0px; width: 25.1%; overflow: hidden; }
.katex .x-arrow-pad { padding: 0px 0.5em; }
.katex .x-arrow, .katex .mover, .katex .munder { text-align: center; }
.katex .boxpad { padding: 0px 0.3em; }
.katex .fbox { box-sizing: border-box; border: 0.04em solid black; }
.katex .fcolorbox { box-sizing: border-box; border: 0.04em solid; }
.katex .cancel-pad { padding: 0px 0.2em; }
.katex .cancel-lap { margin-left: -0.2em; margin-right: -0.2em; }
.katex .sout { border-bottom-style: solid; border-bottom-width: 0.08em; }
.output_wrapper pre code { display: -webkit-box !important; }
.output_wrapper .hljs{color: rgb(169, 183, 198); background: rgb(40, 43, 46); display: block; overflow-x: auto; padding: 0.5em;}

.output_wrapper .hljs-params{color: rgb(255, 152, 35);}

.output_wrapper .hljs-number,.output_wrapper .hljs-literal,.output_wrapper .hljs-symbol,.output_wrapper .hljs-bullet{color: rgb(174, 135, 250);}

.output_wrapper .hljs-function,.output_wrapper .hljs-built_in,.output_wrapper .hljs-name,.output_wrapper .hljs-keyword,.output_wrapper .hljs-selector-tag,.output_wrapper .hljs-deletion{color: rgb(248, 35, 117);}

.output_wrapper .hljs-variable,.output_wrapper .hljs-template-variable,.output_wrapper .hljs-link{color: rgb(98, 151, 85);}

.output_wrapper .hljs-comment,.output_wrapper .hljs-quote{color: rgb(128, 128, 128);}

.output_wrapper .hljs-meta{color: rgb(91, 218, 237);}

.output_wrapper .hljs-string,.output_wrapper .hljs-attribute,.output_wrapper .hljs-addition{color: rgb(238, 220, 112);}

.output_wrapper .hljs-attr,.output_wrapper .hljs-section,.output_wrapper .hljs-title,.output_wrapper .hljs-type{color: rgb(165, 218, 45);}

.output_wrapper .hljs-selector-class{color: rgb(165, 218, 45);}

.output_wrapper .hljs-emphasis{font-style: italic;}

.output_wrapper .hljs-strong{font-weight: bold;}

.output_wrapper pre code {line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0px; letter-spacing: 0px;}
.output_wrapper{font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; word-spacing: 0px; letter-spacing: 0px; font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif; background-image: linear-gradient(90deg, rgba(50, 0, 0, 0.05) 3%, rgba(0, 0, 0, 0) 3%), linear-gradient(360deg, rgba(50, 0, 0, 0.05) 3%, rgba(0, 0, 0, 0) 3%); background-size: 20px 20px; background-position: center center;}

.output_wrapper *{font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px;}

.output_wrapper p{margin: 1.5em 0px;}

.output_wrapper h1,.output_wrapper h2,.output_wrapper h3,.output_wrapper h4,.output_wrapper h5,.output_wrapper h6{margin: 1.5em 0px; font-weight: bold;}

.output_wrapper h1{font-size: 1.6em;}

.output_wrapper h2{font-size: 1.4em;}

.output_wrapper h3{font-size: 1.3em;}

.output_wrapper h4{font-size: 1.2em;}

.output_wrapper h5{font-size: 1em;}

.output_wrapper h6{font-size: 1em;}

.output_wrapper ul,.output_wrapper ol{padding-left: 32px;}

.output_wrapper ul{list-style-type: disc;}

.output_wrapper ol{list-style-type: decimal;}

.output_wrapper li *{}

.output_wrapper li{margin-bottom: 0.5em;}

.output_wrapper .code_size_default{line-height: 18px; font-size: 14px; font-weight: normal; word-spacing: 0px; letter-spacing: 0px;}

.output_wrapper .code_size_tight{line-height: 15px; font-size: 11px; font-weight: normal; word-spacing: -3px; letter-spacing: 0px;}

.output_wrapper pre code{font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px;}

.output_wrapper blockquote{display: block; padding: 15px 15px 15px 1rem; font-size: 0.9em; margin: 1em 0px; color: rgb(129, 145, 152); border-left: 6px solid rgb(220, 230, 240); background: rgb(242, 247, 251); overflow: auto; overflow-wrap: normal; word-break: normal;}

.output_wrapper blockquote p{margin: 0px;}

.output_wrapper a{text-decoration: none; color: rgb(30, 107, 184); overflow-wrap: break-word;}

.output_wrapper strong{font-weight: bold;}

.output_wrapper em{font-style: italic;}

.output_wrapper del{font-style: italic;}

.output_wrapper strong em{font-weight: bold;}

.output_wrapper hr{height: 1px; margin: 1.5rem 0px; border-right: none; border-bottom: none; border-left: none; border-image: initial; border-top: 1px dashed rgb(165, 165, 165);}

.output_wrapper code{overflow-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0px 2px; color: rgb(233, 105, 0); background: rgb(248, 248, 248);}

.output_wrapper img{display: block; margin: 0px auto; max-width: 100%;}

.output_wrapper figcaption{margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;}

.output_wrapper table{display: table; width: 100%; text-align: left;}

.output_wrapper tbody{border: 0px;}

.output_wrapper table tr{border-width: 1px 0px 0px; border-right-style: initial; border-bottom-style: initial; border-left-style: initial; border-right-color: initial; border-bottom-color: initial; border-left-color: initial; border-image: initial; border-top-style: solid; border-top-color: rgb(204, 204, 204); background-color: white;}

.output_wrapper table tr th,.output_wrapper table tr td{font-size: 1em; border: 1px solid rgb(204, 204, 204); padding: 0.5em 1em; text-align: left;}

.output_wrapper table tr th{font-weight: bold; background-color: rgb(240, 240, 240);}

.output_wrapper .katex-display{font-size: 1.22em;}

.output_wrapper .katex{padding: 8px 3px;}

.output_wrapper .katex-display > .katex{display: inline-block; text-align: center; padding: 3px;}

.output_wrapper .katex img{display: inline-block; vertical-align: middle;}

.output_wrapper a[href^="#"] sup{vertical-align: super; margin: 0px 2px; padding: 1px 3px; color: rgb(255, 255, 255); background: rgb(102, 102, 102); font-size: 0.7em;}

.output_wrapper .task-list-list{list-style-type: none;}

.output_wrapper .task-list-list.checked{color: rgb(62, 62, 62);}

.output_wrapper .task-list-list.uncheck{color: rgb(191, 193, 191);}

.output_wrapper .task-list-list .icon_uncheck,.output_wrapper .task-list-list .icon_check{display: inline-block; vertical-align: middle; margin-right: 10px;}

.output_wrapper .task-list-list .icon_check::before{content: "√"; border: 2px solid rgb(62, 62, 62); color: red;}

.output_wrapper .task-list-list .icon_uncheck::before{content: "x"; border: 2px solid rgb(191, 193, 191); color: rgb(191, 193, 191);}

.output_wrapper .task-list-list .icon_check::before,.output_wrapper .task-list-list .icon_uncheck::before{padding: 2px 8px 2px 5px; border-radius: 5px;}

.output_wrapper .toc{margin-left: 25px;}

.output_wrapper .toc_item{display: block;}

.output_wrapper .toc_left{margin-left: 25px;}

.output_wrapper pre code{border-radius: 3px; border-width: 1px 1px 1px 6px; border-style: solid; border-color: rgb(204, 204, 204) rgb(204, 204, 204) rgb(204, 204, 204) rgb(33, 152, 99);}

.output_wrapper pre code .linenum{padding-right: 20px; word-spacing: 0px;}

.output_wrapper .hljs{color: rgb(169, 183, 198); background: rgb(40, 43, 46); display: block; overflow-x: auto; padding: 0.5em;}

.output_wrapper .hljs-params{color: rgb(255, 152, 35);}

.output_wrapper .hljs-number,.output_wrapper .hljs-literal,.output_wrapper .hljs-symbol,.output_wrapper .hljs-bullet{color: rgb(174, 135, 250);}

.output_wrapper .hljs-function,.output_wrapper .hljs-built_in,.output_wrapper .hljs-name,.output_wrapper .hljs-keyword,.output_wrapper .hljs-selector-tag,.output_wrapper .hljs-deletion{color: rgb(248, 35, 117);}

.output_wrapper .hljs-variable,.output_wrapper .hljs-template-variable,.output_wrapper .hljs-link{color: rgb(98, 151, 85);}

.output_wrapper .hljs-comment,.output_wrapper .hljs-quote{color: rgb(128, 128, 128);}

.output_wrapper .hljs-meta{color: rgb(91, 218, 237);}

.output_wrapper .hljs-string,.output_wrapper .hljs-attribute,.output_wrapper .hljs-addition{color: rgb(238, 220, 112);}

.output_wrapper .hljs-attr,.output_wrapper .hljs-section,.output_wrapper .hljs-title,.output_wrapper .hljs-type{color: rgb(165, 218, 45);}

.output_wrapper .hljs-selector-class{color: rgb(165, 218, 45);}

.output_wrapper .hljs-emphasis{font-style: italic;}

.output_wrapper .hljs-strong{font-weight: bold;}

.output_wrapper p{margin: 1.5em 0px;}

.output_wrapper h1,.output_wrapper h2,.output_wrapper h3,.output_wrapper h4,.output_wrapper h5,.output_wrapper h6{margin: 1.5em 0px; font-weight: bold;}

.output_wrapper h1{font-size: 1.6em;}

.output_wrapper h2{font-size: 1.4em;}

.output_wrapper h3{font-size: 1.3em;}

.output_wrapper h4{font-size: 1.2em;}

.output_wrapper h5{font-size: 1em;}

.output_wrapper h6{font-size: 1em;}

.output_wrapper h3{border-bottom: 2px solid rgb(62, 62, 62); margin-bottom: 50px;}

.output_wrapper h3 span{display: inline-block; padding: 10px 0px;}

.output_wrapper h3 span::first-letter,.output_wrapper h3 .firstletter{color: rgb(255, 255, 255); padding: 10px 15px; margin-right: 20px; background: rgb(62, 62, 62);}
-->

原文:How to Create a Simple FPS in Unreal Engine 4
作者:Tommy Tran
译者:Shuchang Liu

在本篇教程中,将学习创建一个简单的第一人称视角射击游戏。你将学会如何创建一个持枪的第一人称角色,并实现射击其他Actor。

第一人称视角射击游戏(FPS)是一类玩家以游戏角色视角进行射击体验的游戏。FPS游戏非常热门,不乏使命召唤和战地等大作。

Unreal引擎最开始就是为FPS游戏量身打造的引擎,所以用Unreal引擎制作FPS游戏也是理所当然的事。在本篇教程中,你将学会:

  • 创建能够四处移动的第一人称角色
  • 创建一把枪,绑定在角色身上
  • 使用直线追踪(大家熟知的射线追踪)发射子弹
  • 对Actor扣除伤害

注意:本篇教程只是Unreal Engine 4系列教程的其中一篇:

起步入门

下载示例项目并解压。进入项目文件夹,双击BlockBreaker.uproject打开项目,我们能看到以下场景:

绿色墙上包含着多个目标,当目标受到伤害时会变红。一旦血量值降为零,目标就会消失。红色按钮可以重置所有的目标。

首先,我们要创建玩家角色。

创建玩家角色

打开Blueprints文件夹并创建一个新的Blueprint Class类,选择Character作为父类,并将其命名为BP_Player。

Character本身是Pawn的一种,额外多了一些其他功能,比如CharacterMovement组件。

该组件会自动处理如走动跑跳等移动功能,我们只要简单调用对应函数就可以移动角色。我们也可以在该组件设置走路速度,起跳速度等变量。

在实现移动功能前,Character需要知道玩家的按键情况,因为我们先将移动映射到W,A,S和D键上。

注意:如果你还不熟悉关于键位映射的有关内容,请查看蓝图教程。键位映射是一种定义键位执行特定行为的方法。

创建移动映射

选择Edit\Project Settings,打开Input设置。

创建两个名为MoveForward和MoveRight的轴映射。MoveForward控制前后移动,MoveRight控制左右移动。

对于MoveForward,将按键改为W,随后,创建多一个键位插槽,将其设置为S,并将Scale改为-1.0。

随后,我们会将Scale值跟角色朝向向量相乘,当Scale值是正数时,向量方向朝前,当Scale值是负数时,向量方向朝后。通过得出的向量结果,我们就可以让角色朝前朝后移动了。

接着,我们要对左右移动做同样的设置,将MoveRight设为D,新建键位插槽设为A,Scale值设为-1.0。

现在我们设置好了键位映射,就可以用它们来进行移动了。

实现移动

打开BP_Player并打开Event Graph,添加MoveForward事件节点(在Axis Events分类下)。即使没有按任何按键,该事件也会每帧调用。

该事件会输出Axis Value,也即刚才所设置的Scale值。当按下W时,输出1,当按下S时,输出-1。如果不按任何按键,输出0。

接着,我们要让角色进行移动,添加Add Movement Input,进行如下连接:

Add Movement Input节点会用一个向量与Scale Value字段相乘,这样就能将向量转换到对应方向。由于我们用了Character类,CharacterMovement组件会将Pawn往对应方向移动向量距离。

现在,我们需要指定移动方向。我们希望角色往正面朝向移动,所以可以使用Get Actor Forward Vector节点,该节点返回一个正面朝向向量,创建节点如图下一样连接:

小结:

  1. MoveForward节点会每帧输出Axis Value,当按下W时输出1,当按下S时输出-1,什么都不按,输出0
  2. Add Movement Input节点将玩家朝向向量与Scale Value相乘,使得不同按键控制输出不同方向的向量。什么都不按,意味着向量并没有方向,角色原地不动
  3. CharacterMovement组件获得Add Movement Input节点的输出,驱动角色朝指定方向移动

MoveRight按以上步骤操作,不过记得将Get Actor Forward Vector节点改为Get Actor Right Vector节点。

在测试移动功能前,我们还要设置下Game Mode里的默认Pawn。

设置默认Pawn

点击Compile并回到主编辑器,打开World Settings面板并找到Game Mode设置,将Default Pawn Class改为BP_Player。

注意:如果你的主编辑器面板还没有World Settings面板,在Toolbar选择Settings\World Settings调出面板。

现在运行游戏你就能控制BP_Player了,按下Play并使用W,S,A和D来进行移动。

我们接着创建输入映射来观察四周。

创建观察映射

打开Project Settings,再创建两个轴映射,分别命名为LookHorizontal和LookVertical。

将LookHorizontal的键位改为Mouse X。

这样当鼠标向右滑动时会输出正数,反之亦然。

接着,将LookVertical的键位改为Mouse Y。

这样当鼠标向上滑动时会输出正数,反之亦然。

现在,我们要写点逻辑来实现转动视角。

实现转动视角

如果一个Pawn上没有Camera组件,Unreal会自动为你创建一个摄像机。默认情况下,摄像机会使用控制器的旋转。

注意:如果你想了解更多关于控制器的内容,可以查看AI部分教程。

虽然控制器并没有物理实体,它仍旧有自己的旋转。这意味着我们可以让角色和摄像机面向不同方向。比如,在第三人称游戏里,角色和摄像机并不总是处于同一方向。

要在第一人称视角里转动摄像机,我们所要做的就是修改控制器的旋转。

打开BP_Player并创建LookHorizontal事件。

要让摄像机看向左边或右边,我们需要调整控制器的偏航角(Yaw),创建Add Controller Yaw Input节点并进行如下连接:

现在,当你水平移动鼠标时,控制器会向左或向右转动,由于摄像机使用了控制器的旋转,摄像机也会跟着转动。

重复以上步骤实现LookVertical,不过记得将Add Controller Yaw Input改为Add Controller Pitch Input节点。

如果我们现在就运行测试游戏,会发现上下转动的反转的,也就是说,当我们鼠标向上滑动,摄像机是向下转动的。

如果想改成非反转控制,将Axis Value剩余-1,这样就能对Axis Value取反,控制器的转动也会反转过来。

点击Compile并按下Play运行游戏,使用鼠标来转动视角吧。

现在移动和视角转动都实现了,是时候搞把枪了!

创建枪支

你还记得当创建蓝图类时,我们可以指定一个父类吧?好吧,其实也可以指定自己的蓝图类作为父类。当我们有多个不同类型的物体,拥有同样的函数或属性时,就会发现很有用处。

举例来说,当我们有多种类型的汽车。我们可以创建一个Car类,包含比如速度和颜色等变量。然后可以再创建其他类(子类),使用Car类作为父类。每个子类都会包含同样的变量。现在我们就能轻易地创建不同速度和颜色变量的汽车了。

我们可以使用相同方式来创建枪支。因为我们首先要创建一个基类。

创建枪支基类

回到主编辑器并创建Actor类型的Blueprint Class,将其命名为BP_BaseGun并打开。

接着,我们要创建一些定义枪械参数的变量,创建如下float类型变量:

  • MaxBulletDistance:子弹最远飞行距离
  • Damage:子弹伤害
  • FireRate:子弹发射间隔(秒)

注意:每个变量的默认值都是0,对本例来说没什么问题。然而,如果你希望新的枪支类有别的默认值,你需要在BP_BaseGun设置下。

现在,我们需要给枪支一个物理外观,添加Static Mesh组件并命名为GunMesh。

先别急着给Static Mesh组件设置网格,我们会在创建枪械子类时再做这件事。

创建枪械子类

点击Compile并返回主编辑器。要创建子类,我们要在右键点击BP_BaseGun,从弹出菜单选中Create Child Blueprint Class。

将其命名为BP_Rifle并双击打开,然后打开Class Default设置以下变量:

  • MaxBulletDistance: 5000
  • Damage: 2
  • FireRate: 0.1

这意味着每颗子弹能最远飞行5000单位的距离。如果子弹命中Actor,能对其造成2点伤害。当持续开火射击时,射击间隔不少于0.1秒。

接着,我们需要指定这把枪的网格,选中GunMesh组件,并将其Static Mesh设置为SM_Rifle。

这把枪现在就完成了,点击Compile并关闭BP_Rifle。

接着,我们要创建自己的摄像机组件了。这样能够更好地控制摄像机位置,我们还可以将枪支跟摄像机绑定在一起,这样枪支就能始终保持在摄像机的正面了。

创建摄像机

打开BP_Player并创建摄像机组件,将其命名为FpsCamera。

摄像机的默认位置有点偏低,会让玩家感觉太矮,将FpsCamera的位置改为(0, 0, 90)。

默认情况下,摄像机组件并不使用控制器的旋转。要修正这点,在Details面板启用Camera Settings\Use Pawn Control Rotation。

接着,我们需要定义枪支的位置。

定义枪支位置

要定义枪支位置,我们可以使用Scene组件。这个组件非常适合用来定义位置,因为它只包含一个Transform。首先确保选中了FpsCamera,然后再创建Scene组件,组件就会附着在摄像机节点下,将组件命名为GunLocation。

通过在FpsCamera放置GunLocation,枪支就会相对于摄像机保持同一位置,这样枪支就能始终保持在镜头前方。

接着,将GunLocation的位置改为(30, 14, -12),让其处于相对摄像机靠前一侧位置。

随后,将旋转设为(0, 0, -95)。当枪支在这个位置时,看起来就像在瞄准屏幕中间。

现在,我们需要生成枪支并将其绑定在GunLocation位置上。

生成并绑定枪支

找到Event BeginPlay并创建Spawn Actor From Class节点,将Class设为BP_Rifle。

由于我们需要用到枪支,先创建变量存储其引用。创建BP_BaseGun类型变量,将其命名为EquippedGun。

这里要注意新建变量不要设为BP_Rifle类型的,因为玩家应该能够使用各种类型的枪支,而不单只是来福枪,否则如果生成了其他种类的枪支,就不能存储在BP_Rifle类型变量上了。

接着,将Spawn Actor From Class的Return Value引脚设为EquippedGun。

要绑定枪支的位置,我们需要用上AttachToComponent组件。创建组件并将Location Rule和Rotation Rule设为Snap to Target。这样就能让枪支拥有跟其父类一样的位置和旋转。

接着,创建GunLocation引用并进行如下连线:

小结:

  1. 当BP_Player生成时,它会连带生成BP_Rifle实例
  2. EquippedGun字段会持有BP_Rifle引用
  3. AttachToComponent节点会将枪支设置在GunLocation位置。

点击Compile并按下Play运行游戏。现在当玩家生成时,枪支也会一同生成,显示在摄像机的前面。

现在有趣的地方来了:射击子弹!要检测子弹是否打中东西,我们要用上射线检测(line trace)。

射击子弹

射线检测是一个包含开始点和结束点(两点成线)的函数,它会检测这条线上的每个点,看是否碰到其他物体。在游戏中,这是用于检测子弹是否打中东西的最普遍做法。

由于射击是属于枪支的特性,射击函数应该设计在枪支类里,而不是角色类。打开BP_BaseGun并创建名为Shoot的函数。

随后,创建两个Vector输入,分别命名为StartLocation和EndLocation。它们分别为射线检测的开始点和结束点(通过BP_Player传入)。

我们可以使用LineTraceByChannel节点来执行射线检测。这个节点会使用可视力(Visibility)或者摄像机(Camera)碰撞通道来进行碰撞检测。创建节点,进行如下连线:

接着,我们需要检测射线是否碰撞到任何东西。创建Branch并进行如下连线:

如果检测到碰撞,Return Value会输出true,反之亦然。

为了在子弹击中物体时给予玩家视觉反馈,我们可以使用粒子特效。

生成子弹撞击粒子

首先,我们需要获得射线碰撞的位置。拖拽Out Hit引脚到图表空白处,从弹出菜单中,选择Break Hit Result。

这样我们能得到一个跟射线检测结果相关的,具有多种引脚的节点。

创建Spawn Emitter at Location节点,并将Emitter Template设为PS_BulletImpact。随后,连接其Location与Break Hit Result的Location。

以下是目前的函数连线:

小结:

  1. 当Shoot函数执行时,它首先会执行一个射线检测
  2. 如果检测到碰撞,Spawn Emitter at Location节点会在碰撞位置生成粒子特效PS_BulletImpact。

现在射击逻辑已经完成了,再写下调用逻辑即可。

调用射击函数

首先,我们需要创建射击的按键映射。点击Compile并打开Project Settings。创建一个新的Axis Mapping并命名为Shoot,将其按键设为Left Mouse Button,然后关闭Project Settings。

随后,打开BP_Player并创建Shoot事件。

为了检测玩家是否按下Shoot键,我们需要检测Axis Value是否等于1。创建如下高亮节点:

接着,创建EquippedGun引用节点,并调用它的Shoot函数。

现在,我们需要计算下射线检测的起始点和结束点。

计算射线检测的位置

在很多FPS游戏里,子弹其实是从摄像机而不是从枪里发射出来的,这是因为摄像机天然就是对准射击准心的。所以如果从摄像机发射子弹,就可以保证其一定会往准心飞行。

注意:也有些游戏确实是从枪里发射子弹的。然而,它要求一些额外计算来保证子弹向准心方向射击。

创建FpsCamera引用并将其与GetWorldLocation连接。

现在我们还需要结束点位置。记得枪支有个MaxBulletDistance变量吧,这意味着结束点位置应该在距离摄像机MaxBulletDistance单位远的地方。因此要计算出结束点位置,添加如下高亮节点:

随后,像下图一样连接所有节点:

小结:

  1. 当玩家按下或按住鼠标左键时,枪支会从摄像机处开始发射子弹。
  2. 子弹会向前飞行MaxBulletDistance距离

点击Compile并按下Play运行游戏,按住鼠标左键开始发射子弹吧!

现在,枪支是每帧都在射击的,射速实在是有点太快了,所以下一步要降低枪支的开火速度。

降低开火速度

首先,我们需要一个变量检测玩家是否正在射击。打开BP_Player创建boolean类型变量,命名为CanShoot,将其默认值设为true。如果CanShoot等于true,说明玩家正在射击。

下面将Branch部分图表改成下图:

现在,玩家只有在按下Shoot键且CanShoot等于true时才能进行射击了。

接着,添加如下高亮节点:

调整修改小结:

  1. 玩家只有在按住鼠标左键且CanShoot等于true时才能进行射击
  2. 一旦玩家射出一颗子弹,CanShoot就会设为false,防止马上射出第二颗子弹
  3. CanShoot会在隔FireRate秒时间后重置为true

点击Compile并关闭BP_Player,按下Play运行游戏测试下枪支的射速吧!

实现受击

在Unreal里,每个Actor都能受击。然而,Actor要对受击伤害做出什么处理是可以自由定义的。

比如,当战斗中的游戏角色当受击时,会扣除血量。然而,像气球一类物体是没有血量概念的。取而代之的,我们会编写逻辑让气球在受击时爆炸。

在我们处理Actor受击时,我们首先要施加一个“伤害”。打开BP_BaseGun并在Shoot函数后添加Apply Damage节点。

接着,我们需要指定要施加伤害的Actor,在本例中,就是射线检测到的Actor。连接Damaged Actor与Break Hit Result的Hit Actor引脚。

最后,我们需要指定要受击伤害数值,创建Damage变量引用,并与Base Damage相连。

现在,当我们调用Shoot函数时,它就会对射线检测到的物体进行伤害。点击Compile并关闭BP_BaseGun。

现在我们需要处理每种Actor对于受击伤害的反馈。

处理受击

首先,我们需要处理目标获得伤害数据,打开BP_Target并创建Event AnyDamage事件节点,这个节点会在受到伤害且其数值不为零时触发执行。

随后,调用TakeDamage函数并连接Damage引脚。这个函数会将目标的Health变量减去Damage数值,并更新目标的颜色。

现在,当目标受到伤害时,它就会扣除血量了。点击Compile并关闭BP_Target。

接着,我们需要处理按钮对伤害的反馈。打开BP_ResetButton并创建Event AnyDamage。随后,调用ResetTargets函数。

这个函数会在按钮受击时调用并重置所有目标的状态。点击Compile并关闭BP_ResetButton。

按下Play运行游戏开始射击目标。如果你想要重置所有目标,就朝按钮射击。

后续学习

你可以在这里下载完整项目。

虽然本篇教程中所制作是一个非常简单的FPS游戏,你可以在此基础上进一步扩展,试着创建更多具有不用射速和伤害的枪械,也可以尝试添加装弹功能!

以上就是Unreal Engine 4 系列教程的全部内容了。不过别担心,我们后续还会制作更多关于Unreal Engine 4的教程。现在我们开始在招募新的Unreal Engine教程团队了,希望可以为社区带来更多精彩的Unreal Engine系列教程。希望到时可以看到你们的身影!:]

Unreal Engine 4 系列教程 Part 10:制作简单FPS游戏的更多相关文章

  1. Unreal Engine 4 系列教程 Part 5:制作简单游戏

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  2. Unreal Engine 4 系列教程 Part 1:入门

    原文:Unreal Engine 4 Tutorial for Beginners: Getting Started 作者:Tommy Tran 译者:Shuchang Liu 本篇教程将引导你安装U ...

  3. Unreal Engine 4 系列教程 Part 2:蓝图教程

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  4. Unreal Engine 4 系列教程 Part 3:材质教程

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  5. Unreal Engine 4 系列教程 Part 4:UI教程

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  6. Unreal Engine 4 系列教程 Part 9:AI教程

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  7. Unreal Engine 4 系列教程 Part 8:粒子系统教程

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  8. Unreal Engine 4 系列教程 Part 7:音频教程

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  9. Unreal Engine 4 系列教程 Part 6:动画教程

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

随机推荐

  1. Sublime和VSCode生成基础HTML代码

    我们在编写前端页面时,常希望能自动生成基础的HTML代码.而在Sublime和VSCode就有这样的功能 在Sublime中,在编辑栏输入html,然后敲Tab键,则自动生成代码如下: <!DO ...

  2. Have a look ^_^

    参考书籍: <重构 改善既有代码的设计 第2版>马丁 福勒著 人民邮电出版社 马丁 福勒的其他著作:<分析模式>,<UML精粹>,<领域特定语言> 目录 ...

  3. rpmbuild打包

    安装: yum  install -y rpm-build 目录介绍: 默认目录在  /root/rpmbuild BUILD :你要打包的文件将会在这里编译(编译rpm包的临时目录) BUILDRO ...

  4. java循环定时器@Scheduled的使用

    @Scheduled 注解 用于定时循环执行任务 例如: @Scheduled(cron="0 */10 * * * ?") 表示每隔十分钟执行一次 每隔5秒执行一次:" ...

  5. DedeCMS V5.7 SP2后台代码执行漏洞复现(CNVD-2018-01221)

    dedeCMS  V5.7 SP2后台代码执行漏洞复现(CNVD-2018-01221) 一.漏洞描述 织梦内容管理系统(Dedecms)是一款PHP开源网站管理系统.Dedecms V5.7 SP2 ...

  6. 关于excel中的vlookup就是查找当前列对应的下一列的值的使用

    关于excel中的vlookup就是查找当前列对应的下一列的值的使用 vlookup的使用一些说明 vlookup函数一个4个参数解释下 vlookup(查找的值,表格范围,表格范围中第几列的值,0是 ...

  7. make 命令与 Makefile

    make 是一个工具程序,通过读取 Makefile 文件,实现自动化软件构建.虽然现代软件开发中,集成开发环境已经取代了 make,但在 Unix 环境中,make 仍然被广泛用来协助软件开发.ma ...

  8. 死磕 java同步系列之ReentrantLock源码解析(一)——公平锁、非公平锁

    问题 (1)重入锁是什么? (2)ReentrantLock如何实现重入锁? (3)ReentrantLock为什么默认是非公平模式? (4)ReentrantLock除了可重入还有哪些特性? 简介 ...

  9. python基础(25):面向对象三大特性二(多态、封装)

    1. 多态 1.1 什么是多态 多态指的是一类事物有多种形态. 动物有多种形态:人,狗,猪. import abc class Animal(metaclass=abc.ABCMeta): #同一类事 ...

  10. Shadow broker=>fuzzbunch+metasploit 攻击外网测试以及metasploit大批量扫描目标IP

    0x01 前言 4月14日,影子经纪人在steemit.com上公开了一大批NSA(美国国家安全局)“方程式组织” (Equation Group)使用的极具破坏力的黑客工具,其中包括可以远程攻破全球 ...