1+ const scene = new THREE . Scene ( )
2+ const camera = new THREE . PerspectiveCamera ( 75 , window . innerWidth / window . innerHeight , 0.1 , 1000 )
3+
4+ const renderer = new THREE . WebGLRenderer ( )
5+ renderer . setSize ( window . innerWidth , window . innerHeight )
6+ document . body . appendChild ( renderer . domElement )
7+
8+ const light = new THREE . AmbientLight ( 0xffffff )
9+ scene . add ( light )
10+
11+ const directionalLight = new THREE . DirectionalLight ( 0xffffff , 0.3 ) ;
12+ directionalLight . castShadow = true
13+ scene . add ( directionalLight )
14+ directionalLight . position . set ( 0 , 1 , 1 )
15+
16+ camera . position . z = 5
17+ renderer . setClearColor ( 0xB7C3F3 , 1 )
18+
19+ const loader = new THREE . GLTFLoader ( )
20+ let doll
21+
22+ const start_position = 6
23+ const end_position = - start_position
24+
25+ const text = document . querySelector ( '.text' )
26+
27+ let DEAD_PLAYERS = 0
28+ let SAFE_PLAYERS = 0
29+
30+ const startBtn = document . querySelector ( '.start-btn' )
31+
32+ //musics
33+ const bgMusic = new Audio ( './music/bg.mp3' )
34+ bgMusic . loop = true
35+ const winMusic = new Audio ( './music/win.mp3' )
36+ const loseMusic = new Audio ( './music/lose.mp3' )
37+
38+ loader . load ( './model/scene.gltf' , function ( gltf ) {
39+ scene . add ( gltf . scene )
40+ doll = gltf . scene
41+ gltf . scene . position . set ( 0 , - 1 , 0 )
42+ gltf . scene . scale . set ( 0.4 , 0.4 , 0.4 )
43+ startBtn . innerText = "start"
44+ } )
45+
46+ function lookBackward ( ) {
47+ gsap . to ( doll . rotation , { duration : .45 , y : - 3.15 } )
48+ setTimeout ( ( ) => dallFacingBack = true , 150 )
49+ }
50+ function lookForward ( ) {
51+ gsap . to ( doll . rotation , { duration : .45 , y : 0 } )
52+ setTimeout ( ( ) => dallFacingBack = false , 450 )
53+ }
54+
55+ function createCube ( size , posX , rotY = 0 , color = 0xfbc851 ) {
56+ const geometry = new THREE . BoxGeometry ( size . w , size . h , size . d )
57+ const material = new THREE . MeshBasicMaterial ( { color } )
58+ const cube = new THREE . Mesh ( geometry , material )
59+ cube . position . set ( posX , 0 , 0 )
60+ cube . rotation . y = rotY
61+ scene . add ( cube )
62+ return cube
63+ }
64+
65+ //Creating runway
66+ createCube ( { w : start_position * 2 + .21 , h : 1.5 , d : 1 } , 0 , 0 , 0xe5a716 ) . position . z = - 1
67+ createCube ( { w : .2 , h : 1.5 , d : 1 } , start_position , - .4 )
68+ createCube ( { w : .2 , h : 1.5 , d : 1 } , end_position , .4 )
69+
70+
71+ class Player {
72+ constructor ( name = "Player" , radius = .25 , posY = 0 , color = 0xffffff ) {
73+ const geometry = new THREE . SphereGeometry ( radius , 100 , 100 )
74+ const material = new THREE . MeshBasicMaterial ( { color } )
75+ const player = new THREE . Mesh ( geometry , material )
76+ scene . add ( player )
77+ player . position . x = start_position - .4
78+ player . position . z = 1
79+ player . position . y = posY
80+ this . player = player
81+ this . playerInfo = {
82+ positionX : start_position - .4 ,
83+ velocity : 0 ,
84+ name,
85+ isDead : false
86+ }
87+ }
88+
89+ run ( ) {
90+ if ( this . playerInfo . isDead ) return
91+ this . playerInfo . velocity = .03
92+ }
93+
94+ stop ( ) {
95+ gsap . to ( this . playerInfo , { duration : .1 , velocity : 0 } )
96+ }
97+
98+ check ( ) {
99+ if ( this . playerInfo . isDead ) return
100+ if ( ! dallFacingBack && this . playerInfo . velocity > 0 ) {
101+ text . innerText = this . playerInfo . name + " lost!!!"
102+ this . playerInfo . isDead = true
103+ this . stop ( )
104+ DEAD_PLAYERS ++
105+ loseMusic . play ( )
106+ if ( DEAD_PLAYERS == players . length ) {
107+ text . innerText = "Everyone lost!!!"
108+ gameStat = "ended"
109+ }
110+ if ( DEAD_PLAYERS + SAFE_PLAYERS == players . length ) {
111+ gameStat = "ended"
112+ }
113+ }
114+ if ( this . playerInfo . positionX < end_position + .7 ) {
115+ text . innerText = this . playerInfo . name + " is safe!!!"
116+ this . playerInfo . isDead = true
117+ this . stop ( )
118+ SAFE_PLAYERS ++
119+ winMusic . play ( )
120+ if ( SAFE_PLAYERS == players . length ) {
121+ text . innerText = "Everyone is safe!!!"
122+ gameStat = "ended"
123+ }
124+ if ( DEAD_PLAYERS + SAFE_PLAYERS == players . length ) {
125+ gameStat = "ended"
126+ }
127+ }
128+ }
129+
130+ update ( ) {
131+ this . check ( )
132+ this . playerInfo . positionX -= this . playerInfo . velocity
133+ this . player . position . x = this . playerInfo . positionX
134+ }
135+ }
136+
137+ async function delay ( ms ) {
138+ return new Promise ( resolve => setTimeout ( resolve , ms ) )
139+ }
140+
141+ const player1 = new Player ( "Player 1" , .25 , .3 , 0xD1FFC6 )
142+ const player2 = new Player ( "Player 2" , .25 , - .3 , 0xFFCFD2 )
143+
144+ const players = [
145+ {
146+ player : player1 ,
147+ key : "ArrowUp" ,
148+ name : "Player 1"
149+ } ,
150+ {
151+ player : player2 ,
152+ key : "w" ,
153+ name : "Player 2"
154+ }
155+ ]
156+
157+ const TIME_LIMIT = 15
158+ async function init ( ) {
159+ await delay ( 500 )
160+ text . innerText = "Starting in 3"
161+ await delay ( 500 )
162+ text . innerText = "Starting in 2"
163+ await delay ( 500 )
164+ text . innerText = "Starting in 1"
165+ lookBackward ( )
166+ await delay ( 500 )
167+ text . innerText = "Gooo!!!"
168+ bgMusic . play ( )
169+ start ( )
170+ }
171+
172+ let gameStat = "loading"
173+
174+ function start ( ) {
175+ gameStat = "started"
176+ const progressBar = createCube ( { w : 8 , h : .1 , d : 1 } , 0 , 0 , 0xebaa12 )
177+ progressBar . position . y = 3.35
178+ gsap . to ( progressBar . scale , { duration : TIME_LIMIT , x : 0 , ease : "none" } )
179+ setTimeout ( ( ) => {
180+ if ( gameStat != "ended" ) {
181+ text . innerText = "Time Out!!!"
182+ loseMusic . play ( )
183+ gameStat = "ended"
184+ }
185+ } , TIME_LIMIT * 1000 )
186+ startDall ( )
187+ }
188+
189+ let dallFacingBack = true
190+ async function startDall ( ) {
191+ lookBackward ( )
192+ await delay ( ( Math . random ( ) * 1500 ) + 1500 )
193+ lookForward ( )
194+ await delay ( ( Math . random ( ) * 750 ) + 750 )
195+ startDall ( )
196+ }
197+
198+
199+ startBtn . addEventListener ( 'click' , ( ) => {
200+ if ( startBtn . innerText == "START" ) {
201+ init ( )
202+ document . querySelector ( '.modal' ) . style . display = "none"
203+ }
204+ } )
205+
206+ function animate ( ) {
207+ renderer . render ( scene , camera )
208+ players . map ( player => player . player . update ( ) )
209+ if ( gameStat == "ended" ) return
210+ requestAnimationFrame ( animate )
211+ }
212+ animate ( )
213+
214+ window . addEventListener ( "keydown" , function ( e ) {
215+ if ( gameStat != "started" ) return
216+ let p = players . find ( player => player . key == e . key )
217+ if ( p ) {
218+ p . player . run ( )
219+ }
220+ } )
221+ window . addEventListener ( "keyup" , function ( e ) {
222+ let p = players . find ( player => player . key == e . key )
223+ if ( p ) {
224+ p . player . stop ( )
225+ }
226+ } )
227+
228+ window . addEventListener ( 'resize' , onWindowResize , false )
229+ function onWindowResize ( ) {
230+ camera . aspect = window . innerWidth / window . innerHeight
231+ camera . updateProjectionMatrix ( )
232+ renderer . setSize ( window . innerWidth , window . innerHeight )
233+ }
0 commit comments