console
const spaceshipModel = {
"uvs": [[0.27906113862991333, 0.33436039090156555, 0.3161470592021942, 0.33436039090156555, 0.2734621465206146, 0.25258663296699524, 0.2734621465206146, 0.15861955285072327, 0.3217460811138153, 0.15861955285072327, 0.3217460811138153, 0.25258663296699524, 0.3105480968952179, 0.41613414883613586, 0.2846601903438568, 0.41613414883613586, 0.23932033777236938, 0.25258663296699524, 0.23932033777236938, 0.18672767281532288, 0.273462176322937, 0.12086869776248932, 0.3217460811138153, 0.12086869776248932, 0.35588791966438293, 0.25258663296699524, 0.35588791966438293, 0.18672767281532288, 0.2528374493122101, 0.33436039090156555, 0.34237074851989746, 0.33436039090156555, 0.3288535475730896, 0.41613414883613586, 0.26635462045669556, 0.41613414883613586, 0.23932033777236938, 0.12086869776248932, 0.2839176058769226, 0.08367034792900085, 0.3112906217575073, 0.08367034792900085, 0.35588791966438293, 0.12086869776248932, 0.2645619511604309, 0.08367034792900085, 0.3306463062763214, 0.08367034792900085, 0.58144611120224, 0.4954613745212555, 0.5310850739479065, 0.4954613745212555, 0.5310850739479065, 0.43834176659584045, 0.58144611120224, 0.43834176659584045, 0.5665895342826843, 0.5510128736495972, 0.5459415316581726, 0.5510128736495972, 0.5310850739479065, 0.38122227787971497, 0.58144611120224, 0.38122227787971497, 0.39441484212875366, 0.24721792340278625, 0.44269871711730957, 0.24721792340278625, 0.44269871711730957, 0.31307685375213623, 0.39441484212875366, 0.31307685375213623, 0.40001386404037476, 0.16544413566589355, 0.43709972500801086, 0.16544413566589355, 0.476840615272522, 0.24721792340278625, 0.476840615272522, 0.31307685375213623, 0.44269871711730957, 0.378935843706131, 0.39441484212875366, 0.378935843706131, 0.36027300357818604, 0.24721792340278625, 0.36027300357818604, 0.31307685375213623, 0.3737901449203491, 0.16544413566589355, 0.40561285614967346, 0.08367034792900085, 0.43150076270103455, 0.08367034792900085, 0.4633234441280365, 0.16544413566589355, 0.476840615272522, 0.378935843706131, 0.43224331736564636, 0.41613414883613586, 0.40487030148506165, 0.41613414883613586, 0.36027300357818604, 0.378935843706131, 0.387307345867157, 0.08367034792900085, 0.44980621337890625, 0.08367034792900085, 0.4515989422798157, 0.41613414883613586, 0.38551464676856995, 0.41613414883613586, 0.5859230756759644, 0.1392219066619873, 0.6362841129302979, 0.1392219066619873, 0.6362841129302979, 0.19634142518043518, 0.5859230756759644, 0.19634142518043518, 0.6007795333862305, 0.08367037773132324, 0.6214274764060974, 0.08367037773132324, 0.6362841129302979, 0.25346091389656067, 0.5859230756759644, 0.25346091389656067, 0.5277184844017029, 0.4935545027256012, 0.5089478492736816, 0.5137609839439392, 0.5089478492736816, 0.44477173686027527, 0.5277184844017029, 0.46497830748558044, 0.4824022650718689, 0.5137609839439392, 0.4824022650718689, 0.44477173686027527, 0.5198169350624084, 0.5401121377944946, 0.4715331494808197, 0.5401120185852051, 0.46363165974617004, 0.4935545027256012, 0.46363168954849243, 0.46497830748558044, 0.4715331196784973, 0.4184206426143646, 0.5198169350624084, 0.4184206426143646, 0.481118768453598, 0.21538829803466797, 0.5294026732444763, 0.21538829803466797, 0.5237872004508972, 0.2971620559692383, 0.4867341220378876, 0.2971620559692383, 0.49434319138526917, 0.19735026359558105, 0.5161781907081604, 0.19735026359558105, 0.5181718468666077, 0.378935843706131, 0.4923495352268219, 0.378935843706131, 0.481118768453598, 0.14952930808067322, 0.49434319138526917, 0.14952930808067322, 0.5294026732444763, 0.14952930808067322, 0.5161781907081604, 0.14952930808067322, 0.481118768453598, 0.08367037773132324, 0.49434319138526917, 0.10170841217041016, 0.5294026732444763, 0.08367037773132324, 0.5161781907081604, 0.10170841217041016, 0.5818047523498535, 0.24721792340278625, 0.5335209369659424, 0.24721792340278625, 0.5391363501548767, 0.16544416546821594, 0.5761893391609192, 0.16544416546821594, 0.5685803294181824, 0.26525595784187317, 0.5467453002929688, 0.26525595784187317, 0.5447517037391663, 0.08367037773132324, 0.5705740451812744, 0.08367037773132324, 0.5818047523498535, 0.3130768835544586, 0.5685803294181824, 0.3130768835544586, 0.5335209369659424, 0.3130768835544586, 0.5467453002929688, 0.3130768835544586, 0.5818047523498535, 0.378935843706131, 0.5685803294181824, 0.36089783906936646, 0.5335209369659424, 0.378935843706131, 0.5467453002929688, 0.36089783906936646, 0.4384301006793976, 0.4184206426143646, 0.46026504039764404, 0.4184206426143646, 0.4602651596069336, 0.5165088772773743, 0.4384301006793976, 0.5165088772773743, 0.343448668718338, 0.4184206426143646, 0.3892560601234436, 0.4184206426143646, 0.3892560601234436, 0.5165088772773743, 0.3642469644546509, 0.5165088772773743, 0.43506351113319397, 0.4184206426143646, 0.4142652750015259, 0.5165088772773743, 0.2942747175693512, 0.4184206426143646, 0.3400821089744568, 0.4184206426143646, 0.3192838728427887, 0.5165088772773743, 0.2942747175693512, 0.5165088772773743, 0.24846728146076202, 0.4184206426143646, 0.2692655026912689, 0.5165088772773743, 0.23932038247585297, 0.518795371055603, 0.2611554265022278, 0.518795371055603, 0.261155366897583, 0.6168836355209351, 0.23932033777236938, 0.6168837547302246, 0.2869286835193634, 0.6168837547302246, 0.2650936245918274, 0.6168837547302246, 0.2650936245918274, 0.518795371055603, 0.2869286835193634, 0.518795371055603, 0.40804117918014526, 0.6168836355209351, 0.3622337579727173, 0.6168836355209351, 0.3622337579727173, 0.518795371055603, 0.3872429132461548, 0.518795371055603, 0.31642627716064453, 0.6168836355209351, 0.3372245728969574, 0.518795371055603, 0.4574131667613983, 0.6404868364334106, 0.41160571575164795, 0.6404868364334106, 0.4324040114879608, 0.5423985719680786, 0.4574131667613983, 0.5423985719680786, 0.5032205581665039, 0.6404868364334106, 0.4824222922325134, 0.5423985719680786, 0.312595009803772, 0.6168836355209351, 0.29075998067855835, 0.6168836355209351, 0.2907600402832031, 0.518795371055603, 0.31259506940841675, 0.518795371055603, 0.6765620112419128, 0.17023292183876038, 0.6547271013259888, 0.17023292183876038, 0.6404640674591064, 0.1392219066619873, 0.6908251047134399, 0.1392219066619873, 0.6547271013259888, 0.19634142518043518, 0.6404640674591064, 0.19634142518043518, 0.6553205847740173, 0.08367037773132324, 0.6759685277938843, 0.08367037773132324, 0.6765620112419128, 0.19634142518043518, 0.6908251047134399, 0.19634142518043518, 0.6547271013259888, 0.2224498689174652, 0.6404640674591064, 0.25346091389656067, 0.6765620112419128, 0.2224498689174652, 0.6908251047134399, 0.25346091389656067, 0.6995301842689514, 0.33897534012794495, 0.7213651537895203, 0.33897534012794495, 0.7356281876564026, 0.3699863851070404, 0.6852671504020691, 0.3699863851070404, 0.7213651537895203, 0.3128668963909149, 0.7356281876564026, 0.3128668963909149, 0.7207716107368469, 0.42553797364234924, 0.7001236081123352, 0.42553797364234924, 0.6995301842689514, 0.3128668963909149, 0.6852671504020691, 0.3128668963909149, 0.7213651537895203, 0.2867583930492401, 0.7356281876564026, 0.25574734807014465, 0.6995301842689514, 0.2867583930492401, 0.6852671504020691, 0.25574734807014465, 0.6928291916847229, 0.4278244078159332, 0.6928291916847229, 0.44938012957572937, 0.673616349697113, 0.44938012957572937, 0.673616349697113, 0.4278245270252228, 0.6819005012512207, 0.3112989366054535, 0.6819005012512207, 0.368418425321579, 0.6350399255752563, 0.368418425321579, 0.6350399255752563, 0.3112989366054535, 0.6819005012512207, 0.42553797364234924, 0.6350399255752563, 0.42553797364234924, 0.6488637924194336, 0.25574734807014465, 0.6680766344070435, 0.25574734807014465, 0.7418656945228577, 0.14078986644744873, 0.7418656945228577, 0.19790935516357422, 0.6950049996376038, 0.19790935516357422, 0.6950049996376038, 0.14078986644744873, 0.7280418872833252, 0.25346091389656067, 0.7088289260864258, 0.25346091389656067, 0.7418656945228577, 0.08367034792900085, 0.6950049996376038, 0.08367034792900085, 0.6702137589454651, 0.4278244078159332, 0.6702137589454651, 0.48039916157722473, 0.623353123664856, 0.48039916157722473, 0.623353123664856, 0.42782434821128845, 0.6971439123153687, 0.4493800699710846, 0.6971439123153687, 0.4278244078159332, 0.7163567543029785, 0.4278244078159332, 0.7163568139076233, 0.4493800699710846, 0.7389947772026062, 0.369986355304718, 0.7389947772026062, 0.31286686658859253, 0.7858554124832153, 0.31286686658859253, 0.7858554124832153, 0.369986355304718, 0.7389947772026062, 0.25574734807014465, 0.7858554124832153, 0.25574734807014465, 0.7720314860343933, 0.4255378544330597, 0.7528187036514282, 0.4255378544330597, 0.5848127603530884, 0.368418425321579, 0.5848127603530884, 0.3112989366054535, 0.6316733360290527, 0.3112989366054535, 0.6316733360290527, 0.368418425321579, 0.5986365079879761, 0.25574734807014465, 0.6178493499755859, 0.25574734807014465, 0.5848127603530884, 0.42553797364234924, 0.6316733360290527, 0.42553797364234924, 0.5730898380279541, 0.6058740615844727, 0.5730898976325989, 0.5532993078231812, 0.619950532913208, 0.5532994270324707, 0.6199504733085632, 0.6058741807937622, 0.5067851543426514, 0.5994353294372559, 0.5067851543426514, 0.5724095106124878, 0.5250442624092102, 0.5532993078231812, 0.5250442624092102, 0.618545413017273, 0.5508666634559631, 0.5532993078231812, 0.5508666634559631, 0.618545413017273, 0.5691258311271667, 0.5724095106124878, 0.5691258311271667, 0.5994353294372559, 0.4800853729248047, 0.8318504095077515, 0.48004066944122314, 0.7808135747909546, 0.6538245677947998, 0.7793998122215271, 0.6538715362548828, 0.8330054879188538, 0.28433334827423096, 0.7643555402755737, 0.2844071686267853, 0.848599910736084, 0.47724205255508423, 0.7514933347702026, 0.6989283561706543, 0.7513282299041748, 0.6990244388580322, 0.8610098958015442, 0.4773380756378174, 0.8611749410629272]],
"faces": [41, 48, 49, 50, 51, 232, 233, 234, 235, 0, 1, 2, 3, 41, 1, 2, 38, 39, 2, 8, 9, 3, 4, 5, 6, 7, 41, 88, 89, 90, 91, 24, 25, 26, 27, 8, 9, 10, 11, 41, 3, 4, 36, 37, 42, 32, 35, 43, 12, 13, 14, 15, 41, 4, 5, 35, 36, 32, 33, 34, 35, 16, 17, 18, 19, 41, 5, 6, 34, 35, 33, 38, 39, 34, 20, 21, 22, 23, 41, 94, 95, 96, 97, 56, 57, 58, 59, 24, 25, 26, 27, 41, 7, 0, 32, 33, 12, 5, 4, 13, 28, 29, 30, 31, 41, 8, 9, 17, 16, 11, 10, 19, 20, 32, 33, 34, 35, 41, 9, 10, 18, 17, 10, 18, 22, 19, 36, 37, 38, 39, 41, 10, 11, 19, 18, 70, 71, 68, 65, 40, 41, 42, 43, 41, 11, 12, 20, 19, 51, 41, 50, 55, 44, 45, 46, 47, 41, 12, 13, 21, 20, 41, 40, 49, 50, 48, 49, 50, 51, 41, 13, 14, 22, 21, 40, 48, 54, 49, 52, 53, 54, 55, 41, 14, 15, 23, 22, 74, 75, 66, 69, 56, 57, 58, 59, 41, 15, 8, 16, 23, 21, 11, 20, 23, 60, 61, 62, 63, 41, 17, 18, 23, 16, 64, 65, 66, 67, 64, 65, 66, 67, 41, 41, 49, 48, 40, 236, 233, 232, 237, 68, 1, 0, 69, 41, 2, 1, 41, 42, 8, 2, 0, 14, 5, 4, 70, 71, 41, 3, 2, 42, 43, 76, 77, 78, 79, 72, 73, 74, 75, 41, 4, 3, 43, 44, 32, 42, 44, 36, 13, 12, 76, 77, 41, 5, 4, 44, 45, 33, 32, 36, 37, 17, 16, 78, 79, 41, 6, 5, 45, 46, 38, 33, 37, 47, 21, 20, 80, 81, 41, 7, 6, 46, 47, 92, 93, 94, 95, 82, 83, 84, 85, 41, 0, 7, 47, 40, 5, 12, 15, 1, 29, 28, 86, 87, 41, 33, 32, 8, 15, 13, 4, 11, 21, 31, 30, 88, 89, 41, 97, 96, 98, 99, 59, 58, 62, 63, 27, 26, 90, 91, 41, 35, 34, 14, 13, 34, 39, 48, 40, 23, 22, 92, 93, 41, 36, 35, 13, 12, 35, 34, 40, 41, 19, 18, 94, 95, 41, 37, 36, 12, 11, 43, 35, 41, 51, 15, 14, 96, 97, 41, 91, 90, 92, 93, 27, 26, 30, 31, 11, 10, 98, 99, 41, 39, 38, 10, 9, 3, 9, 18, 10, 7, 6, 100, 101, 41, 32, 39, 9, 8, 4, 3, 10, 11, 102, 103, 104, 105, 41, 41, 40, 24, 25, 0, 1, 6, 7, 106, 107, 108, 109, 41, 42, 41, 25, 26, 14, 0, 7, 17, 71, 70, 110, 111, 41, 43, 42, 26, 27, 79, 78, 82, 83, 75, 74, 112, 113, 41, 44, 43, 27, 28, 36, 44, 52, 45, 77, 76, 114, 115, 41, 45, 44, 28, 29, 37, 36, 45, 46, 79, 78, 116, 117, 41, 46, 45, 29, 30, 47, 37, 46, 53, 81, 80, 118, 119, 41, 47, 46, 30, 31, 95, 94, 98, 99, 85, 84, 120, 121, 41, 40, 47, 31, 24, 1, 15, 16, 6, 87, 86, 122, 123, 41, 1, 39, 50, 49, 238, 239, 234, 233, 124, 125, 126, 127, 41, 39, 32, 51, 50, 239, 240, 235, 234, 128, 129, 130, 131, 41, 32, 0, 48, 51, 240, 241, 232, 235, 132, 133, 134, 135, 40, 0, 40, 48, 241, 237, 232, 133, 136, 134, 40, 41, 1, 49, 236, 238, 233, 137, 124, 127, 41, 2, 3, 53, 52, 77, 76, 80, 81, 73, 72, 138, 139, 41, 3, 37, 54, 53, 76, 84, 85, 80, 72, 140, 141, 138, 41, 38, 2, 52, 55, 86, 77, 81, 87, 142, 73, 139, 143, 41, 37, 11, 56, 54, 84, 88, 89, 85, 140, 144, 145, 141, 41, 11, 10, 57, 56, 88, 90, 91, 89, 144, 146, 147, 145, 41, 10, 38, 55, 57, 90, 86, 87, 91, 146, 142, 143, 147, 41, 6, 7, 59, 58, 93, 92, 96, 97, 83, 82, 148, 149, 41, 7, 33, 60, 59, 92, 100, 101, 96, 82, 150, 151, 148, 41, 34, 6, 58, 61, 102, 93, 97, 103, 152, 83, 149, 153, 41, 33, 15, 62, 60, 100, 104, 105, 101, 150, 154, 155, 151, 41, 15, 14, 63, 62, 104, 106, 107, 105, 154, 156, 157, 155, 41, 14, 34, 61, 63, 106, 102, 103, 107, 156, 152, 153, 157, 41, 52, 53, 65, 64, 108, 109, 110, 111, 158, 159, 160, 161, 41, 53, 54, 66, 65, 112, 113, 114, 115, 162, 163, 164, 165, 41, 55, 52, 64, 67, 118, 119, 120, 121, 166, 167, 168, 169, 41, 54, 56, 68, 66, 113, 116, 117, 114, 163, 170, 171, 164, 41, 56, 57, 69, 68, 124, 125, 126, 127, 172, 173, 174, 175, 41, 57, 55, 67, 69, 122, 118, 121, 123, 176, 166, 169, 177, 41, 58, 59, 71, 70, 128, 129, 130, 131, 178, 179, 180, 181, 41, 59, 60, 72, 71, 132, 133, 134, 135, 182, 183, 184, 185, 41, 61, 58, 70, 73, 138, 139, 140, 141, 186, 187, 188, 189, 41, 60, 62, 74, 72, 133, 136, 137, 134, 183, 190, 191, 184, 41, 62, 63, 75, 74, 144, 145, 146, 147, 192, 193, 194, 195, 41, 63, 61, 73, 75, 142, 138, 141, 143, 196, 186, 189, 197, 41, 64, 65, 77, 76, 148, 149, 150, 151, 198, 199, 200, 201, 41, 65, 66, 78, 77, 149, 152, 153, 150, 199, 202, 203, 200, 41, 67, 64, 76, 79, 156, 148, 151, 157, 204, 198, 201, 205, 41, 66, 68, 80, 78, 152, 158, 159, 153, 202, 206, 207, 203, 41, 68, 69, 81, 80, 158, 160, 161, 159, 206, 208, 209, 207, 41, 69, 67, 79, 81, 160, 156, 157, 161, 208, 204, 205, 209, 41, 70, 71, 83, 82, 162, 163, 164, 165, 210, 211, 212, 213, 41, 71, 72, 84, 83, 163, 166, 167, 164, 211, 214, 215, 212, 41, 73, 70, 82, 85, 170, 162, 165, 171, 216, 210, 213, 217, 41, 72, 74, 86, 84, 166, 172, 173, 167, 214, 218, 219, 215, 41, 74, 75, 87, 86, 172, 174, 175, 173, 218, 220, 221, 219, 41, 75, 73, 85, 87, 174, 170, 171, 175, 220, 216, 217, 221, 41, 100, 101, 102, 103, 176, 177, 178, 179, 222, 223, 224, 225, 41, 77, 78, 90, 89, 180, 181, 182, 183, 226, 227, 228, 229, 41, 79, 76, 88, 91, 188, 189, 190, 191, 230, 231, 232, 233, 41, 78, 80, 92, 90, 181, 184, 185, 182, 227, 234, 235, 228, 41, 80, 81, 93, 92, 196, 197, 198, 199, 236, 237, 238, 239, 41, 81, 79, 91, 93, 194, 188, 191, 195, 240, 230, 233, 241, 41, 104, 105, 106, 107, 200, 201, 202, 203, 242, 243, 244, 245, 41, 83, 84, 96, 95, 204, 205, 206, 207, 246, 247, 248, 249, 41, 85, 82, 94, 97, 212, 213, 214, 215, 250, 251, 252, 253, 41, 84, 86, 98, 96, 205, 208, 209, 206, 247, 254, 255, 248, 41, 86, 87, 99, 98, 220, 221, 222, 223, 256, 257, 258, 259, 41, 87, 85, 97, 99, 218, 212, 215, 219, 260, 250, 253, 261, 41, 76, 77, 101, 100, 151, 150, 154, 155, 201, 200, 262, 263, 41, 77, 89, 102, 101, 180, 183, 186, 187, 226, 229, 264, 265, 41, 89, 88, 103, 102, 25, 24, 28, 29, 9, 8, 266, 267, 41, 88, 76, 100, 103, 190, 189, 192, 193, 232, 231, 268, 269, 41, 82, 83, 105, 104, 165, 164, 168, 169, 213, 212, 270, 271, 41, 83, 95, 106, 105, 204, 207, 210, 211, 246, 249, 272, 273, 41, 95, 94, 107, 106, 57, 56, 60, 61, 25, 24, 274, 275, 41, 94, 82, 104, 107, 214, 213, 216, 217, 252, 251, 276, 277, 41, 25, 24, 31, 26, 224, 225, 226, 227, 278, 279, 280, 281, 41, 23, 18, 19, 22, 66, 65, 68, 69, 66, 65, 282, 283, 41, 22, 19, 20, 21, 69, 68, 72, 73, 283, 282, 284, 285, 41, 27, 30, 29, 28, 229, 228, 230, 231, 286, 287, 288, 289, 41, 26, 31, 30, 27, 227, 226, 228, 229, 281, 280, 287, 286],
"vertices": [1.67042317, 4.03275896, -4.36502924, -1.67042395, 4.03275948, -4.36502924, -4.03276001, 1.67042382, -4.36502924, -4.03275844, -1.67042317, -4.36502924, -1.67042382, -4.03276001, -4.36502924, 1.6704233, -4.0327587, -4.36502924, 4.03276105, -1.67042395, -4.36502924, 4.03275896, 1.67042356, -4.36502924, 1.67042382, 4.03276001, 4.36502924, -1.67042317, 4.03275844, 4.36502924, -4.03276001, 1.67042382, 4.36502924, -4.03275844, -1.67042317, 4.36502924, -1.67042382, -4.03276001, 4.36502924, 1.6704233, -4.0327587, 4.36502924, 4.03276105, -1.67042395, 4.36502924, 4.03275896, 1.67042356, 4.36502924, 0.94699426, 2.2171378, 6.83047695, -0.94699446, 2.21713858, 6.83047695, -2.2862468, 0.91836833, 6.83047695, -2.2862468, -0.91836839, 6.83047695, -0.94699446, -2.21713858, 6.83047695, 0.94699433, -2.21713728, 6.83047695, 2.28624732, -0.91836891, 6.83047695, 2.28624758, 0.91836891, 6.83047695, 0.89561503, 2.15673196, -15.20470413, -0.89561483, 2.15673196, -15.20470413, -2.16220502, 0.89334727, -15.20470413, -2.16220489, -0.89334727, -15.20470413, -0.89561425, -2.15673117, -15.20470413, 0.89561509, -2.15673222, -15.20470413, 2.16220515, -0.89334733, -15.20470413, 2.1622058, 0.89334766, -15.20470413, 1.67042317, 4.03275896, 1.86296253, 4.03275896, 1.67042356, 0.0, 4.03276105, -1.67042395, 0.0, 1.6704233, -4.0327587, 0.0, -1.67042382, -4.03276001, -0.0, -4.03275844, -1.67042317, -0.0, -4.03276001, 1.67042382, -0.0, -1.67042395, 4.03275948, 1.86296253, 1.28301848, 3.09474637, -9.78486616, -1.28301952, 3.09474637, -9.78486616, -3.0974829, 1.28188567, -9.78486616, -3.09748108, -1.28188567, -9.78486616, -1.28301874, -3.09474611, -9.78486616, 1.28301939, -3.09474637, -9.78486616, 3.09748342, -1.28188541, -9.78486616, 3.09748368, 1.28188567, -9.78486616, 0.77727793, 5.34595995, -4.28712837, -0.7772791, 5.34596255, -4.28712837, -0.81640073, 5.37902884, 0.59514022, 0.81640008, 5.37902884, 0.59514035, -4.03276001, 0.75540272, -3.1694965, -4.03275896, -0.75540298, -3.1694965, -4.03275896, -0.75540298, 0.0, -4.03276001, 0.75540272, 0.0, -4.03275896, -0.75540298, 3.1694965, -4.03276001, 0.75540272, 3.1694965, 4.03276105, -0.75540285, -3.1694965, 4.03276053, 0.75540318, -3.1694965, 4.03276053, 0.75540318, 0.0, 4.03276105, -0.75540285, 0.0, 4.03276053, 0.75540318, 3.1694965, 4.03276105, -0.75540285, 3.1694965, -10.53389522, 0.75539869, -1.73042744, -10.53389834, -0.75540598, -1.73042744, -10.53389834, -0.75540598, 0.0, -10.53389522, 0.75539869, 0.0, -10.53389834, -0.75540598, 1.73042744, -10.53389522, 0.75539869, 1.73042744, 10.5338973, -0.75539791, -1.73042757, 10.53389834, 0.75540598, -1.73042757, 10.53389834, 0.75540598, 0.0, 10.5338973, -0.75539791, 0.0, 10.53389834, 0.75540598, 1.73042757, 10.5338973, -0.75539791, 1.73042757, -10.53389626, 1.74228327, -3.78579078, -10.53389522, -1.74228977, -3.78579078, -10.53389522, -1.74228977, 0.0, -10.53389626, 1.74228327, 0.0, -10.53389522, -1.74228977, 3.78579078, -10.53389626, 1.74228327, 3.78579078, 10.53389626, -1.74228327, -3.78579104, 10.53389314, 1.74228977, -3.78579104, 10.53389314, 1.74228977, 0.0, 10.53389626, -1.74228327, 0.0, 10.53389314, 1.74228977, 3.78579104, 10.53389626, -1.74228327, 3.78579104, -13.77626911, 1.74228171, -3.78579078, -13.77626703, -1.74229133, -3.78579078, -13.77626703, -1.74229133, 0.0, -13.77626911, 1.74228171, 0.0, -13.77626703, -1.74229133, 3.78579078, -13.77626911, 1.74228171, 3.78579078, 13.77626911, -1.7422765, -3.78579104, 13.7762639, 1.74229472, -3.78579104, 13.7762639, 1.74229472, 0.0, 13.77626911, -1.7422765, 0.0, 13.7762639, 1.74229472, 3.78579104, 13.77626911, -1.7422765, 3.78579104, -11.49039488, 0.71433355, -7.4676605, -11.49039488, -0.71434109, -7.4676605, -12.81976632, -0.71434213, -7.4676605, -12.81976736, 0.71433303, -7.4676605, 11.49039592, -0.71433199, -7.4676605, 11.4903928, 0.71434213, -7.4676605, 12.81976528, 0.71434396, -7.4676605, 12.81976736, -0.71432991, -7.4676605],
"normals": [6.7e-07, 0.97012001, -0.24262564, 6.7e-07, 0.97012007, -0.24262556, 8.2e-07, 0.99997711, -0.0067728, 8.2e-07, 0.99997699, -0.0067728, -0.70478702, 0.70491242, -0.07983695, -0.70478618, 0.70491159, -0.07985092, -0.70710677, 0.70710683, 6e-08, -0.70710665, 0.70710683, 1.3e-07, -0.99557716, -8e-07, -0.09394732, -0.99557716, -8e-07, -0.09394733, -1.0, -6.9e-07, 0.0, -1.0, -6.9e-07, 0.0, -0.70428789, -0.70442569, -0.08810792, -0.70428884, -0.70442653, -0.08809391, -0.70710707, -0.70710647, 0.0, -0.70710707, -0.70710647, 0.0, 3e-07, -0.99609917, -0.08823975, 3e-07, -0.99609923, -0.08823976, 3.9e-07, -1.0, 0.0, 3.9e-07, -1.0, 0.0, 0.70428818, -0.70442724, -0.08809389, 0.70428717, -0.70442629, -0.08810788, 0.70710635, -0.70710719, 0.0, 0.70710635, -0.70710719, 0.0, 0.9955771, 1.42e-06, -0.09394721, 0.99557728, 1.42e-06, -0.09394721, 1.0, 1.38e-06, 0.0, 1.0, 1.38e-06, 0.0, 0.704786, 0.70491171, -0.07985087, 0.70478684, 0.70491254, -0.07983689, 0.70710677, 0.70710689, -1.4e-07, 0.70710665, 0.70710689, -6e-08, 0.0, 0.80521572, 0.59298211, 0.0, 0.80521566, 0.59298211, 0.0, 0.80521572, 0.59298205, 0.0, 0.80521566, 0.59298205, -0.57000715, 0.57631028, 0.5856263, -0.57000715, 0.57631034, 0.5856263, -0.57000721, 0.57631034, 0.58562636, -0.57000715, 0.57631022, 0.5856263, -0.81600052, -2.2e-07, 0.57805121, -0.81600046, -2.2e-07, 0.57805115, -0.81600046, -2.2e-07, 0.57805115, -0.81600046, -2.2e-07, 0.57805115, -0.5700075, -0.57630998, 0.58562642, -0.5700075, -0.57630998, 0.58562636, -0.5700075, -0.57630992, 0.5856263, -0.5700075, -0.57631004, 0.58562642, 4.3e-07, -0.80521542, 0.59298223, 4.3e-07, -0.80521554, 0.59298235, 4.3e-07, -0.80521554, 0.59298235, 4.3e-07, -0.80521548, 0.59298235, 0.57000673, -0.57631052, 0.5856266, 0.57000679, -0.57631046, 0.5856266, 0.57000679, -0.57631052, 0.5856266, 0.57000667, -0.57631046, 0.5856266, 0.8160004, 3.6e-07, 0.57805127, 0.81600052, 3.6e-07, 0.57805127, 0.8160004, 3.6e-07, 0.57805121, 0.8160004, 3.6e-07, 0.57805121, 0.57000726, 0.57631016, 0.58562648, 0.57000721, 0.57631016, 0.58562654, 0.57000721, 0.5763101, 0.58562648, 0.57000721, 0.5763101, 0.58562648, 8e-08, 0.0, 1.0, 1.2e-07, 0.0, 1.0, 1.2e-07, 0.0, 1.0, 8e-08, 0.0, 1.0, 5.6e-07, 0.92542064, -0.37894154, 5.6e-07, 0.92542058, -0.37894154, -0.69647926, 0.69707721, -0.17029381, -0.69647926, 0.69707727, -0.17029382, -0.98989505, -5.5e-07, -0.14180169, -0.98989516, -5e-07, -0.14180169, -0.98543501, -5.3e-07, -0.17005213, -0.98543507, -5.3e-07, -0.17005214, -0.69647944, -0.69707704, -0.17029382, -0.69647944, -0.69707698, -0.17029382, 1e-08, -0.98535162, -0.17053528, 1e-08, -0.9853515, -0.17053528, 0.6964792, -0.69707739, -0.17029384, 0.69647908, -0.69707739, -0.17029384, 0.98989505, 4.1e-07, -0.14180163, 0.98989511, 2.6e-07, -0.14180163, 0.98543507, 1.3e-07, -0.17005213, 0.98543507, 1.3e-07, -0.17005213, 0.69647908, 0.69707745, -0.17029372, 0.69647914, 0.69707745, -0.17029372, 0.70710677, 0.70710677, -2.5e-07, 0.70710677, 0.70710677, -2.5e-07, 1.0, 1.38e-06, 0.0, 1.0, 1.38e-06, 0.0, 0.70710635, -0.70710719, 0.0, 0.70710635, -0.70710719, 0.0, 3.9e-07, -1.0, 0.0, 3.9e-07, -1.0, 0.0, -0.70710707, -0.70710647, 0.0, -0.70710707, -0.70710647, 0.0, -1.0, -6.9e-07, 0.0, -1.0, -6.9e-07, 0.0, -0.70710659, 0.70710695, 2.2e-07, -0.70710659, 0.70710695, 2.2e-07, -1.6e-07, 1.0, 4e-08, -1.6e-07, 1.0, 4e-08, -1.6e-07, 1.0, 4e-08, -1.6e-07, 1.0, 4e-08, 0.0, 0.98535156, -0.17053531, 0.0, 0.9853515, -0.17053531, 0.0, 0.98535162, -0.17053531, 0.0, 0.98535162, -0.17053534, -0.69623393, 0.69732225, -0.17029394, -0.69623387, 0.69732219, -0.17029393, -0.98543507, -4.7e-07, -0.17005213, -0.98543507, -4.7e-07, -0.17005213, -0.69623399, -0.69732225, -0.17029387, -0.69623399, -0.69732225, -0.17029387, -2.8e-07, -0.98535162, -0.17053537, -2.8e-07, -0.98535162, -0.17053537, 0.69623393, -0.69732225, -0.17029397, 0.69623387, -0.69732219, -0.17029396, 0.98543501, -9e-08, -0.17005229, 0.98543501, -9e-08, -0.17005226, 0.69623369, 0.69732243, -0.1702939, 0.69623369, 0.69732255, -0.17029391, -0.83032686, 0.55419791, -0.05849712, -0.83670509, 0.54763466, -0.0045761, -0.83670503, 0.54763466, -0.0045761, -0.83232862, 0.55255836, -0.04368601, 3e-08, 0.68557835, 0.72799885, 3e-08, 0.68557835, 0.72799885, 3e-08, 0.68557829, 0.72799897, 3e-08, 0.68557829, 0.72799897, 0.83670491, 0.54763484, -0.00457626, 0.83032662, 0.55419832, -0.05849725, 0.83232838, 0.5525586, -0.04368616, 0.83670497, 0.54763484, -0.00457626, 0.81253374, 0.56184107, -0.15531714, -0.81253433, 0.56184018, -0.15531701, -1.0, -5.4e-07, -9e-08, -1.0, -1.7e-07, -9e-08, -1.0, -6.6e-07, 0.0, -1.0, -6.6e-07, 0.0, -1.0, -0.0, 0.0, -1.0, -0.0, 0.0, -1.0, -5.1e-07, 1.2e-07, -1.0, -5.4e-07, 9e-08, -1.0, -2.1e-07, 1.2e-07, -1.0, -1.7e-07, 9e-08, 1.0, 1.19e-06, -2.8e-07, 1.0, 6e-08, -2.8e-07, 1.0, 1.65e-06, 0.0, 1.0, 1.65e-06, 0.0, 1.0, -2.5e-07, 0.0, 1.0, -2.5e-07, 0.0, 1.0, 1.07e-06, 3.5e-07, 1.0, 1.19e-06, 2.8e-07, 1.0, 2.4e-07, 3.5e-07, 1.0, 1.6e-07, 2.8e-07, -0.21612491, 1.1e-07, -0.9763658, -0.21612491, 1.1e-07, -0.97636575, -0.21612491, 1.1e-07, -0.9763658, -0.21612488, 1.1e-07, -0.97636569, 4.6e-07, -1.0, 0.0, 4.6e-07, -1.0, 0.0, 4.6e-07, -1.0, 0.0, 4.6e-07, -1.0, 0.0, -6.2e-07, 1.0, 0.0, -6.2e-07, 1.0, 0.0, -6.2e-07, 0.99999994, 0.0, -6.2e-07, 1.0, 0.0, 4.6e-07, -1.0, 0.0, 4.6e-07, -1.0, 0.0, -0.21612494, 1.1e-07, 0.97636575, -0.21612495, 1.1e-07, 0.9763658, -0.21612492, 1.1e-07, 0.97636569, -0.21612492, 1.1e-07, 0.97636575, -6.2e-07, 1.0, 0.0, -6.2e-07, 0.99999994, 0.0, 0.21612486, -1.1e-07, -0.97636575, 0.21612485, -1.1e-07, -0.97636575, 0.21612485, -1.1e-07, -0.97636575, 0.21612485, -1.1e-07, -0.97636575, -4.3e-07, 1.0, 0.0, -4.3e-07, 1.0, 0.0, -4.3e-07, 1.0, 0.0, -4.3e-07, 1.0, 0.0, 7.6e-07, -1.0, 0.0, 7.6e-07, -1.0, 0.0, 7.6e-07, -0.99999994, 0.0, 7.6e-07, -1.0, 0.0, -4.3e-07, 1.0, 0.0, -4.3e-07, 1.0, 0.0, 0.21612485, -1.1e-07, 0.97636569, 0.21612488, -1.1e-07, 0.97636575, 0.21612485, -1.1e-07, 0.97636575, 0.21612485, -1.1e-07, 0.97636575, 7.6e-07, -1.0, 0.0, 7.6e-07, -0.99999994, 0.0, 1.0, 6.9e-07, 3e-07, 0.99999994, 1.38e-06, 3e-07, 0.98692763, 2.1e-07, -0.16116452, 0.98692757, 1.1e-07, -0.16116451, 1.0, 3.34e-06, 0.0, 1.0, 3.34e-06, 0.0, 1.0, 1.25e-06, 0.0, 1.0, 1.25e-06, 0.0, 1.0, 1.38e-06, -3e-07, 1.0, 5.8e-07, -4.2e-07, 0.99999994, 3.5e-07, -3e-07, 1.0, 1.5e-07, -4.2e-07, -1.0, 6.9e-07, 8.9e-07, -1.0, -2.07e-06, 8.9e-07, -0.98692757, -9.4e-07, -0.16116431, -0.98692769, -5.2e-07, -0.16116431, -1.0, -5.01e-06, 0.0, -1.0, -5.01e-06, 0.0, -0.99999994, 1.25e-06, 0.0, -0.99999994, 1.25e-06, 0.0, -1.0, -2.07e-06, -8.9e-07, -1.0, -8.7e-07, -1.25e-06, -1.0, 3.5e-07, -8.9e-07, -1.0, 1.5e-07, -1.25e-06, -3.5e-07, 0.0, -0.99999994, -3.5e-07, 0.0, -1.0, -3.5e-07, 0.0, -1.0, -3.5e-07, 0.0, -1.0, 5.2e-07, -0.99480468, -0.10180275, 4.8e-07, -1.0, 0.0, 4.8e-07, -1.0, 0.0, 5.2e-07, -0.99480456, -0.10180271, -4.8e-07, 1.0, 0.0, -4.8e-07, 0.99480462, -0.10180279, -4.8e-07, 0.99480456, -0.10180277, -4.8e-07, 1.0, 0.0, 4.8e-07, -1.0, 0.0, 4.8e-07, -1.0, 0.0, -2e-08, 0.0, 0.99999994, -2e-08, 0.0, 1.0, -2e-08, 0.0, 1.0, -2e-08, 0.0, 0.99999994, -4.8e-07, 1.0, 0.0, -4.8e-07, 1.0, 0.0, -4.1e-07, 0.0, -1.0, -4.1e-07, 0.0, -1.0, -4.1e-07, 0.0, -1.0, -4.1e-07, 0.0, -1.0, -1.5e-06, 0.99480456, -0.1018028, -1.52e-06, 1.0, 0.0, -1.52e-06, 1.0, 0.0, -1.5e-06, 0.99480462, -0.10180277, 2.09e-06, -1.0, 0.0, 2e-06, -0.99480456, -0.10180269, 2e-06, -0.99480462, -0.10180271, 2.09e-06, -1.0, 0.0, -1.52e-06, 1.0, 0.0, -1.52e-06, 1.0, 0.0, -5e-08, 0.0, 1.0, -5e-08, 0.0, 1.0, -5e-08, 0.0, 1.0, -5e-08, 0.0, 1.0, 2.09e-06, -1.0, 0.0, 2.09e-06, -1.0, 0.0, 0.96787292, 0.0, -0.25144008, 0.96787292, 0.0, -0.25144008, 5.8e-07, -0.96316576, -0.26890826, 5.8e-07, -0.96316582, -0.26890829, -0.96787274, -9.7e-07, -0.25144055, -0.9678728, -9.7e-07, -0.25144058, -4.5e-07, 0.96316582, -0.26890826, -4.5e-07, 0.96316576, -0.26890826, -0.96787274, -9.7e-07, -0.2514402, -0.9678728, -9.7e-07, -0.2514402, -1.43e-06, 0.96316576, -0.26890838, -1.43e-06, 0.96316576, -0.26890838, 0.96787274, 1.46e-06, -0.25144032, 0.96787286, 1.46e-06, -0.25144032, 1.82e-06, -0.96316582, -0.26890829, 1.82e-06, -0.96316576, -0.26890823, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, -2.4e-07, 0.0, -0.99999994, -2.4e-07, 0.0, -1.0, 1.1e-07, 0.0, 0.99999994, 1.1e-07, 0.0, 0.99999994, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, -1.2e-07, 0.0, -1.0, -1.2e-07, 0.0, -1.0, 5.9e-07, 0.0, -1.0, 5.9e-07, 0.0, -1.0]
}
const RGB = {
fragPars: '#define RGB( r, g, b ) vec3( float( r ) / 255.0, float( g ) / 255.0, float( b ) / 255.0 )',
};
const spaceshipShader = {
vertexShader: `
varying vec2 vUv;
varying vec3 vPosition;
void main() {
vUv = uv;
vPosition = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
precision mediump float;
${RGB.fragPars}
varying vec2 vUv;
varying vec3 vPosition;
void main() {
vec4 color1 = vec4(RGB(255, 0, 255), 0.0);
vec4 color2 = vec4(RGB(0, 255, 255), 0.0);
// if (vUv.y > .7) {
// color = vec4(RGB(0, 255, 255), 0.0);
// }
gl_FragColor = mix(color1, color2, vPosition.y / 10. + .5);
}
`,
wireframe: true,
};
const treeShader = {
uniforms: THREE.UniformsLib.fog,
vertexShader: `
uniform vec3 mvPosition;
varying vec2 vUv;
varying float fogDepth;
void main() {
fogDepth = -mvPosition.z;
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
precision mediump float;
${THREE.ShaderChunk.fog_pars_fragment}
varying vec2 vUv;
void main() {
vec4 color = vec4(.0, 1. - (vUv.y * 1.6), 1. - (vUv.y * .8), 1.); // 1. - vUv.y * 2.
gl_FragColor = color;
#ifdef USE_FOG
#ifdef USE_LOGDEPTHBUF_EXT
float depth = gl_FragDepthEXT / gl_FragCoord.w;
#else
float depth = gl_FragCoord.z / gl_FragCoord.w;
#endif
float fogFactor = smoothstep(fogNear, fogFar, depth);
gl_FragColor.a = gl_FragColor.a * (1. - fogFactor);
#endif
}
`,
fog: true,
transparent: true,
};
const backgroundShader = {
uniforms: {},
vertexShader: `
attribute vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
varying vec2 vUv;
void main() {
gl_Position = vec4(position, 1.0);
vUv = vec2(position.x, position.y) * 0.5 + 0.5;
}
`,
fragmentShader: `
precision mediump float;
${RGB.fragPars}
varying vec2 vUv;
float lmap(in float val, in float inMin, in float inMax, in float outMin, in float outMax) {
return clamp(outMin + ((outMax - outMin) * (val - inMin)) / (inMax - inMin), outMin, outMax);
}
// gradient with multiple colors in non-equal intervals
vec3 getColor(in float perc) {
vec3 uColors[4];
float uStops[4];
const int uNumColors = 4;
uStops[0] = 0.0;
uStops[1] = 0.28;
uStops[2] = 0.58;
uStops[3] = 1.0;
uColors[0] = RGB(255, 146, 48);
uColors[1] = RGB(202, 84, 194);
uColors[2] = RGB(36, 16, 142);
uColors[3] = RGB(2, 0, 36);
for (int i = 1; i < uNumColors; i ++) {
if (perc < uStops[i]) {
float stopPct = lmap(perc, uStops[i-1], uStops[i], 0.0, 1.0);
return mix(uColors[i-1], uColors[i], stopPct);
}
}
// edge case, in case the last stop is not at 1.0
return uColors[uNumColors - 1];
}
float blendColorDodge(float base, float blend) {
return (blend==1.0)?blend:min(base/(1.0-blend),1.0);
}
vec3 blendColorDodge(vec3 base, vec3 blend) {
return vec3(blendColorDodge(base.r,blend.r), blendColorDodge(base.g,blend.g), blendColorDodge(base.b,blend.b));
}
vec3 blendColorDodge(vec3 base, vec3 blend, float opacity) {
return blendColorDodge(base, blend) * opacity + base * (1.0 - opacity);
}
vec3 radialGradient(vec2 center, float radius) {
float distance = length( center - vUv.xy );
float maxDistance = radius;//pow( radius, 0.23);
float quadDistance = distance;//pow( distance, 0.23);
float quadIntensity = 1.0 - min( quadDistance, maxDistance )/maxDistance;
return vec3(quadIntensity);
}
void main() {
float y = vUv.y * 1.1 - .25;
vec3 color = RGB(140, 0, 255) * y; // vec3(0.0, y, y); //vec3(0.0, y, y);
if (vUv.y > .5) {
vec3 sunset = getColor((vUv.y - .5) * 2.);
vec3 light = radialGradient(vec2(.5,.2), .8);
color = blendColorDodge(sunset, light);
}
gl_FragColor = vec4(color, 1.0);
}
`,
side: THREE.DoubleSide,
depthTest: false,
};
const keys = {
W: 1 << 0,
A: 1 << 1,
S: 1 << 2,
D: 1 << 3,
SPACE: 1 << 4,
ENTER: 1 << 5,
ESC: 1 << 6,
SHIFT: 1 << 7,
CTRL: 1 << 8,
LEFT: 1 << 9,
UP: 1 << 10,
RIGHT: 1 << 11,
DOWN: 1 << 12,
};
const keyCodes = {
87: keys.W,
65: keys.A,
83: keys.S,
68: keys.D,
32: keys.SPACE,
13: keys.ENTER,
27: keys.ESC,
16: keys.SHIFT,
17: keys.CTRL,
37: keys.LEFT,
38: keys.UP,
39: keys.RIGHT,
40: keys.DOWN,
};
let keysPressed = 0;
const isKeyDown = keyFlag => Boolean(keysPressed & keyFlag);
const onKeyDown = ({ keyCode }) => {
const keyFlag = keyCodes[keyCode];
keysPressed |= keyFlag;
};
const onKeyUp = ({ keyCode }) => {
keysPressed &= ~keyCodes[keyCode];
};
window.addEventListener('keyup', onKeyUp);
window.addEventListener('keydown', onKeyDown);
const addUniformsToShader = (shader, uniforms) => ({ ...shader, uniforms: { ...shader.uniforms, ...uniforms } });
const random = (min, max, round = false) => {
const num = (Math.random() * (max - min)) + min;
return round ? Math.floor(num + 1) : num;
}
let scene, camera, renderer;
let playerGeometry, playerMaterial, player;
let backgroundGeometry, backgroundMaterial, background;
let time = performance.now();
let timePlaying = 0;
const trees = [];
const treeCount = 500;
const treeHeight = 100;
let treePlaceInterval;
let treePlaceLastTime = time;
let score = 0;
const scoreIncrease = 10;
const scoreUpdateInterval = 500;
let scoreUpdateLastTime = time;
const scoreNodes = document.querySelectorAll('.js-score');
let speed = 600;
const speedIncrease = 3;
let playerSpeed = 0;
const playerAcceleration = 70;
const playerMaxSpeed = 700;
const gameStates = {
PLAYING: 1,
GAME_OVER: 2,
};
let gameState = gameStates.PLAYING;
loadAssets();
function init() {
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0xFF00FF, 1100, 2000);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 50, 0);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', resize);
attachDOMListeners();
createObjects();
requestAnimationFrame(update);
}
function loadAssets() {
const loader = new THREE.JSONLoader();
playerGeometry = loader.parse(spaceshipModel).geometry;
init();
}
function reset() {
hideGameOver();
while (scene.children.length) {
scene.remove(scene.children[0]);
}
trees.length = 0;
score = 0;
createObjects();
time = performance.now();
timePlaying = 0;
gameState = gameStates.PLAYING;
}
function createObjects() {
backgroundGeometry = new THREE.PlaneGeometry(2, 2, 1);
backgroundMaterial = new THREE.RawShaderMaterial(backgroundShader);
background = new THREE.Mesh(backgroundGeometry, backgroundMaterial);
background.frustumCulled = false;
scene.add(background);
playerMaterial = new THREE.ShaderMaterial(spaceshipShader);
player = new THREE.Mesh(playerGeometry, playerMaterial);
player.position.set(0, 20, -45);
scene.add(player);
createTrees();
}
function createTrees() {
const geometry = new THREE.ConeGeometry(12, treeHeight, 4);
const uniforms = {
fogColor: { value: scene.fog.color },
fogNear: { value: scene.fog.near },
fogFar: { value: scene.fog.far },
};
const shader = addUniformsToShader(treeShader, uniforms);
const material = new THREE.ShaderMaterial(shader);
for (let i = 0; i < treeCount; i++) {
const mesh = new THREE.Mesh(geometry, material);
const scale = random(1, 2);
mesh.scale.set(1, scale, 1);
mesh.rotateY(Math.PI * random(0, 0.5));
mesh.inUse = false;
mesh.visible = false;
trees.push(mesh);
scene.add(mesh);
}
}
function getTree() {
let tree;
let i = 0;
do {
tree = trees[i];
i++;
} while (tree.inUse === true && i < treeCount);
return tree;
}
function placeTree() {
const tree = getTree();
const offsetY = (treeHeight * tree.scale.y) / 2;
tree.inUse = true;
tree.visible = true;
tree.position.set(random(camera.position.x - 2500, camera.position.x + 2500), offsetY, -2000);
}
function removeTree(i) {
trees[i].inUse = false;
trees[i].visible = false;
}
function updateTrees(delta) {
for (let i = 0; i < trees.length; i++) {
if (!trees[i].inUse === true) continue;
trees[i].position.z += speed * delta;
checkCollision(trees[i].position.x, trees[i].position.z);
if (trees[i].position.z > 10) {
removeTree(i);
}
}
if (time - treePlaceLastTime >= treePlaceInterval) {
placeTree();
treePlaceLastTime = time;
}
}
function updatePlayer(delta) {
let targetSpeed = 0;
if (isKeyDown(keys.A) || isKeyDown(keys.LEFT)) {
targetSpeed = -playerMaxSpeed;
} else if (isKeyDown(keys.D) || isKeyDown(keys.RIGHT)) {
targetSpeed = playerMaxSpeed;
}
if (playerSpeed < targetSpeed) {
playerSpeed += playerAcceleration;
} else if (playerSpeed > targetSpeed) {
playerSpeed -= playerAcceleration;
}
player.position.x += playerSpeed * delta;
player.rotation.z = -playerSpeed * 0.0006;
camera.position.x = player.position.x;
camera.updateProjectionMatrix();
}
function checkCollision(x, z) {
if (Math.abs(player.position.z - z) < 20 && Math.abs(player.position.x - x) < 25) {
gameState = gameStates.GAME_OVER;
showGameOver();
}
}
function attachDOMListeners() {
const nodes = document.querySelectorAll('.js-play');
Array.prototype.forEach.call(nodes, node => node.addEventListener('click', reset));
}
function updateScore() {
if (time - scoreUpdateLastTime >= scoreUpdateInterval) {
score += scoreIncrease;
scoreUpdateLastTime = time;
}
Array.prototype.forEach.call(scoreNodes, node => node.innerHTML = score);
}
function showGameOver() {
document.getElementById('gameover').style.visibility = 'visible';
}
function hideGameOver() {
document.getElementById('gameover').style.visibility = 'hidden';
}
function resize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function update(newTime) {
requestAnimationFrame(update);
const delta = (newTime - time) / 1000;
time = newTime;
if (delta > 0.5) return;
renderer.render(scene, camera);
if (gameState !== gameStates.PLAYING) return;
timePlaying += delta;
speed += speedIncrease * delta;
treePlaceInterval = (1 / speed) * 40 * 1000;
updateTrees(delta);
updatePlayer(delta);
updateScore();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.min.js"></script>
<div class="GUI">
<div class="score">Score: <output class="score-amount js-score">0</span></output></div>
<div class="instructions">Use A/D or arrow keys to move</div>
<div id="gameover" class="overlay-wrapper">
<div class="overlay">
<h2 class="overlay-title">Game Over</h2>
<div class="overlay-score">Score: <output class="score-amount js-score">0</output></div>
<button class="overlay-button js-play">Play Again</button>
</div>
</div>
</div>
body {
margin: 0;
padding: 0;
overflow: hidden;
color: white;
font-family: Courier New, Courier, monospace;
}
*, *::before, *::after {
box-sizing: border-box;
}
.GUI {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
}
.score {
position: absolute;
top: 60px;
left: 30px;
font-size: 2rem;
}
.instructions {
position: absolute;
top: 30px;
left: 30px;
}
.overlay-wrapper {
visibility: hidden;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
.overlay {
display: flex;
flex-direction: column;
padding: 40px;
background-color: rgba(0, 0, 0, .3);
border: 3px solid rgba(0, 0, 0, .2);
text-align: center;
}
.overlay-title {
margin: 0;
position: relative;
text-transform: uppercase;
font-size: 4rem;
line-height: 1;
font-weight: 300;
mix-blend-mode: screen;
&::before {
content: "Game Over";
position: absolute;
font-weight: 700;
background-image: linear-gradient(to bottom, #00ffff 0%, #ff00ff 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
filter: blur(3px);
z-index: -1;
text-shadow: none;
}
}
.overlay-score {
margin: 30px 0;
font-size: 1.6rem;
text-shadow: 0 0 12px rgba(0, 255, 255, .8);
}
.overlay-button {
margin: 0 auto;
padding: 15px 30px;
border: 3px solid white;
position: relative;
text-shadow: 0 0 12px rgba(0, 255, 255, .8);
appearance: none;
cursor: pointer;
outline: none;
background-color: transparent;
color: white;
font-family: Courier New, Courier, monospace;
font-size: 1.6rem;
&::before {
content: "";
display: block;
width: calc(100% + 6px);
height: calc(100% + 6px);
border: 3px solid white;
border-image: linear-gradient(to bottom, #00ffff 0%, #ff00ff 100%) 10;
position: absolute;
top: -3px;
left: -3px;
z-index: -1;
transition-duration: 200ms;
transition-property: filter, border-width, top, left, width, height;
}
}
.overlay-button:hover::before {
border-width: 9px;
filter: blur(2px);
top: -6px;
left: -6px;
width: calc(100% + 12px);
height: calc(100% + 12px);
}