#VRML V2.0 utf8 # ------------------------------------------------------- # ## AirHockey Game ## ## Author : Jon-Paul Mulholland ## ## Date : 4th May 1999 ## ## Course : Virtual Reality ## ## Specification : VRML 2 ## # ------------------------------------------------------- # PROTO Scores [ exposedField SFColor _TextColor 1 1 1 field SFVec3f _Player1Translation -3 2 -4.5 field SFVec3f _Player1ScoreTranslation -3.25 1.15 -4.5 field SFVec3f _ComputerTranslation 3 2 -4.5 field SFVec3f _ComputerScoreTranslation 3.25 1.15 -4.5 exposedField SFVec3f _GoalTranslation 0 -1 -2 exposedField MFString _Set_Player_String "PLAYER 1:" exposedField MFString _Set_Player_Score "0" exposedField MFString _Set_Computer_String "COMPUTER:" exposedField MFString _Set_Computer_Score "0" field SFRotation _Rotation 1 0 0 -1.25 ] { PROTO ScoreValues [ exposedField MFString _Set_Player_Score "0" exposedField MFString _Set_Computer_Score "0" exposedField SFVec3f _GoalTranslation 0 -1 -2 ] { Transform { ## ---- This Prototype Is here so i can access and set values to ---- ## ## ---- Th exposedFields later on in the Script. ---- ## } } Transform { children [ ## ---- Timer For The ColorInterpolator ---- ## DEF Timer TimeSensor { cycleInterval .5 loop TRUE } ## ---- The Interpolator For Changing the colours ---- ## ## ---- for The Text ---- ## DEF ColInter ColorInterpolator { key [ 0 .5 1 ] keyValue [ 1 0 0, 0 1 0, 0 0 1 ] } Transform { translation IS _Player1Translation rotation IS _Rotation children [ Shape { appearance Appearance { material Material { diffuseColor IS _TextColor } } geometry Text { string IS _Set_Player_String fontStyle FontStyle { justify "MIDDLE" family "SANS" style "BOLD" size .3 } } } ] #p1 } #p1 Transform { translation IS _Player1ScoreTranslation rotation IS _Rotation children [ Shape { appearance Appearance { material Material { diffuseColor IS _TextColor } } geometry Text { string IS _Set_Player_Score fontStyle FontStyle { justify "MIDDLE" family "SANS" style "BOLD" size .75 } } } ] #P1Score } #P1Score Transform { translation IS _ComputerTranslation rotation IS _Rotation children [ Shape { appearance Appearance { material DEF NewCol Material { diffuseColor IS _TextColor } } geometry Text { string IS _Set_Computer_String fontStyle FontStyle { justify "MIDDLE" family "SANS" style "BOLD" size .3 } } } ] #p1 } #p1 Transform { translation IS _ComputerScoreTranslation rotation IS _Rotation children [ Shape { appearance Appearance { material DEF NewCol Material { diffuseColor IS _TextColor } } geometry Text { string IS _Set_Computer_Score fontStyle FontStyle { justify "MIDDLE" family "SANS" style "BOLD" size .75 } } } ] #P1Score } #P1Score DEF GoalParent Transform { translation IS _GoalTranslation children [ DEF goalText Shape { appearance Appearance { material DEF m Material { diffuseColor 0 1 0} } geometry Text { string ["G O A L"] fontStyle FontStyle { justify "MIDDLE" family "SANS" style "BOLD" size 1.25 } } } ] } ] #Root } #Root ## ---- Route Time Change From the Timer To The Interpolator ---- ## ROUTE Timer.fraction_changed TO ColInter.set_fraction ## ---- Route The New Value From The Interpolator to the Diffusecolor ---- ## ROUTE ColInter.value_changed TO NewCol.set_diffuseColor } ## ---- Proto Type For The Puck and The Paddel. It Also Updates ---- ## ## ---- The Position of the Puck and makes it bounce off the ---- ## ## ---- Walls And the Paddel. When the Puck Goes into the Goal ---- ## ## ---- The Puck Goes Back To the Center. The Scores also get ---- ## ## ---- Updated From here as well. PROTO GamingObject [ exposedField SFVec3f _TranslationPaddel 0 0 0 exposedField SFVec3f _Scale 1 1 1 field SFVec3f _Size .75 .25 .25 field SFFloat rad .5 exposedField SFColor _PaddelColor 1 0 0 exposedField SFVec3f _TranslationPuck 0 0 0 exposedField SFVec3f _VelocityPuck 0 0 -1 exposedField SFVec3f _ScalePuck 1 1 1 exposedField SFColor _PuckColor 0 0 0 ## ---- Script Fields ---- # field SFBool playing FALSE field SFFloat random 0 eventIn SFTime StartGame ] { ## ---- Nested Proto So I Can Access The ExposedFields In The ---- ## ## ---- Script. ---- ## PROTO Properties [ exposedField SFVec3f _TranslationPuck 0 0 0 exposedField SFVec3f _TranslationPaddel 0 0 0 exposedField SFVec3f _VelocityPuck 0 0 -1 ] { Transform { ## ---- This Prototype Is here so i can access and set values to ---- ## ## ---- Th exposedFields later on in the Script. ---- ## } } Transform { children [ DEF system Transform { ## ---- This Is for the Roalling Goal children [ ] } DEF properties Properties { _TranslationPuck IS _TranslationPuck _TranslationPaddel IS _TranslationPaddel } ## ---- Define the Paddel For Player 1 ---- ## DEF paddel_parent Transform { translation IS _TranslationPaddel scale IS _Scale children [ ## ---- Define The Plane Sensor For The Paddel ---- ## ## ---- The Paddel Will not go beyond the Max ---- ## ## ---- and Min Positions Set here ---- ## DEF planeSensor PlaneSensor { maxPosition 2.5 0 minPosition -2.5 0 offset 0 0 -.5 } ## ---- Draw The Box For The Paddel ---- ## Shape { appearance Appearance { material Material { diffuseColor IS _PaddelColor } } #geometry Box { #size IS _Size geometry Cylinder {height 0.1 radius 0.25 } } ] } ## ---- End Of Paddel Transform ---- ## ## ---- Start Of The Puck Definition --- ## ## ---- The Puck Transform, Defines The Shape ---- ## ## ---- of the Puck ---- ## Transform { translation IS _TranslationPuck scale IS _ScalePuck children [ ## ---- The Timer For The Script To Get Flowing Motion ---- ## ## ---- Of The Puck ---- ## DEF PuckTimer TimeSensor { cycleInterval 100 loop TRUE } ## ---- Define A TouchSensor For The Puck. So ---- ## ## ---- When The User Presses The Puck It Starts ---- ## ## ---- To Move at a random Velocity. (See Script) ---- ## DEF PuckSensor TouchSensor { } Shape { appearance Appearance { material Material { diffuseColor IS _PuckColor } } geometry Cylinder { height .1 radius .25 } } ] } Transform { children [ ## ---- Display The Scores, By DEF'ing the Scores ---- ## ## ---- This Allows Me To Refrence Them Later To ---- ## ## ---- So I Can Change The Number Of The Score. ---- ## DEF theScores Scores { } ] } DEF Wait TimeSensor { cycleInterval 0.1 loop TRUE } ## ---- The Script To Control The Movement Of The Puck. ---- ## DEF Control Script { field SFNode properties USE properties field SFNode thescores USE theScores field SFBool playing FALSE field SFFloat random 0 eventIn SFBool StartGame eventIn SFFloat time_fraction field SFInt32 playerScore 0 field SFInt32 computerScore 0 eventIn SFBool upateScores eventIn SFBool reserScores eventIn SFInt32 Goal eventOut SFTime waitTimer url "javascript: // ---- The StartGame Function Sets The Playing Flag To TRUE When // ---- You Have Pressed The Puck To Start. function StartGame(value, ts) { if (playing) return; // OtherWise You Are Not Playing. playing = TRUE; } // ---- This function resets the scores of both the player and the, // ---- the computer back to 0. By creating a new MFSting in it's // ---- place. the (''+playerscore) is tge code which displays the // ---- new score. The (''+s was used to give the function the correct // ---- data type to create the string. Without it Cosmo would complain // ---- about the wrong type being assigned to the new MFString. function resetScores (value, ts) { playerScore = 0; thescores._Set_Player_Score = new MFString(''+playerScore); computerScore = 0; thescores._Set_Computer_Score = new MFString(''+computerScore); } // ---- This function Updates the score for either the computer or // ---- the player. The function knows who has scored via the Bool // ---- value that is passed to it. If it is TRUE then the Player // ---- has scored, otherwise it is FALSE and then the compute has // ---- scored. The running total of the scores are kept in the // ---- PlayerScore and the ComputerScore fields, which are converted // ---- to a MFString and displayed. The (''+ was used to give the // ---- function the correct data type to create the string. Without it // ---- Cosmo would complain about the wrong type being assigned to the // ---- new MFString. function updateScores (value, ts) { if(value == TRUE) { if (playerScore >= 10) { resetScores(); playing = FALSE; } else { playerScore += 1; thescores._Set_Player_Score = new MFString(''+playerScore); } } else { if (computerScore >= 10) { resetScores(); playing = FALSE; } else { computerScore += 1; thescores._Set_Computer_Score = new MFString(''+computerScore); } } } // ---- Sets the Position Of the Puck To The Middel Of The Field ---- ## // -- This Gets Called When The WRL Is first Loaded into the Browser -- ## function initialize () { properties._TranslationPuck[0] = 0.0; properties._TranslationPuck[1] = 0.0; properties._TranslationPuck[2] = -3.0; properties._VelocityPuck[0] = .1;//Math.random() - .5; properties._VelocityPuck[1] = 0; // Set To 0, Not moving UP. properties._VelocityPuck[2] = Math.random() - .9; playing = FALSE; } // ---- This Function sets the position for the puck to travel. // ---- It checks to see it the position will touch the walls, // ---- If it does it inverts the sign bit and send's the puck // ---- back at a different velocity. If the Puck goes into the // ---- goal The puck gets recreated at the starting point in the // ---- middel of the field, and the scores get updated. function time_fraction (fraction , eventTime) { if(!playing) return; // OtherWise Set the New Position Of The Puck properties._TranslationPuck[0] += properties._VelocityPuck[0]; properties._TranslationPuck[2] += properties._VelocityPuck[2]; if(properties._TranslationPuck[0] <= -2.5) { properties._TranslationPuck[0] = -2.5; properties._VelocityPuck[0] = -properties._VelocityPuck[0]; } else if (properties._TranslationPuck[0] >= 2.5) { properties._TranslationPuck[0] = 2.5; properties._VelocityPuck[0] = -properties._VelocityPuck[0]; } if (properties._TranslationPuck[2] <= -5.5) { if (properties._TranslationPuck[2] <= -5.5 && properties._TranslationPuck[0] <= .75 && properties._TranslationPuck[0] >= -.75) { properties._TranslationPuck[2] = -6.5; properties._VelocityPuck[2] = -properties._VelocityPuck[2]; // inc Score For Player 1r updateScores(TRUE); // Call the initialize function to reset the board initialize(); playing = FALSE; } else { properties._TranslationPuck[2] = -5.25; properties._VelocityPuck[2] = -properties._VelocityPuck[2]; } } else if (properties._TranslationPuck[2] >= -.25) { if (properties._TranslationPuck[2] >= -.25 && properties._TranslationPuck[0] <= .75 && properties._TranslationPuck[0] >= -.75) { properties._TranslationPuck[2] = 1; // Send Past ViewPoint // inc Score For computer updateScores(FALSE); // Call the initialize function to reset the board initialize(); playing = FALSE; } else { properties._TranslationPuck[2] = -0.5; properties._VelocityPuck[2] = -properties._VelocityPuck[2]; } } // ---- Check for collision with the puck and the paddle. I split the puck and the paddle // ---- in to quarters. So i could calculate the dirction of the puck to bounce off in. if(properties._TranslationPaddel[0] + .25 >= properties._TranslationPuck[0] - .25 && properties._TranslationPaddel[0] - .25 <= properties._TranslationPuck[0] + .25 && properties._TranslationPaddel[2] + .25 >= properties._TranslationPuck[2] - .25 && properties._TranslationPaddel[2] - .25 <= properties._TranslationPuck[2] + .25 ) { // Top left corner of the the Paddle and bottom right of the puck. if(properties._TranslationPuck[0] + .225 && properties._TranslationPuck[2] + .225 < properties._TranslationPaddel[0] - .225 && properties._TranslationPaddel[2] - .225 ) { properties._TranslationPuck[2] = properties._TranslationPaddel[2] - .4; // The .4 is just out side of the puck properties._VelocityPuck[0] = Math.tan(-properties._VelocityPuck[0]); properties._VelocityPuck[2] = Math.tan(-properties._VelocityPuck[2]); } else { // ---- Top right of the paddle and bottom left of the puck. if(properties._TranslationPuck[0] - .225 && properties._TranslationPuck[2] + .225 < properties._TranslationPaddel[0] + .225 && properties._TranslationPaddel[2] - .225 ) { properties._TranslationPuck[2] = properties._TranslationPaddel[2] - .4; // The .4 is just out side of the puck properties._VelocityPuck[0] = Math.tan(-properties._VelocityPuck[0]); properties._VelocityPuck[2] = Math.tan(-properties._VelocityPuck[2]); } else { // ---- bottom left of the paddle and top right of the puck. if(properties._TranslationPuck[0] + .225 || properties._TranslationPuck[2] - .225 < properties._TranslationPaddel[0] - .225 || properties._TranslationPaddel[2] + .225 ) { properties._TranslationPuck[0] = properties._TranslationPaddel[0] - .4; // The .4 is just out side of the puck properties._VelocityPuck[0] = Math.tan(-properties._VelocityPuck[0]); properties._VelocityPuck[2] = Math.tan(-properties._VelocityPuck[2]); } else { // ---- bottom right of the paddle and top left of the puck. if(properties._TranslationPuck[0] - .225 || properties._TranslationPuck[2] - .225 < properties._TranslationPaddel[0] + .15 || properties._TranslationPaddel[2] + .15 ) { properties._TranslationPuck[2] = properties._TranslationPaddel[2] - .4 // The .4 is just out side of the puck properties._VelocityPuck[2] = Math.tan(-properties._VelocityPuck[2]); properties._VelocityPuck[0] = Math.tan(-properties._VelocityPuck[0]); } } } } } } " } ] # Root } # Root ## ---- The ROUTE To Move The Paddel Across The Plane ---- ## ROUTE planeSensor.translation_changed TO paddel_parent.set_translation ## ---- ROUTE The TouchTime Of The TouchSensor From The Puck ---- ## ## ---- To The StartGame Function IN The Script ---- ## ROUTE planeSensor.isActive TO Control.StartGame ## ---- ROUTE The Clock change signl from the timer to the ---- ## ## ---- Script So you get a flowing motion of the puck moving ---- ## ROUTE PuckTimer.fraction_changed TO Control.time_fraction } ## ---- End Of GamingObjects Prototype ---- ## PROTO theField [ field SFVec3f _Blocksize 6 .25 .25 field SFVec3f _Scale 1 1 1 exposedField SFColor _SideColor 1 1 1 exposedField SFColor _FloorColor .2 .6 .5 ] { Transform { scale IS _Scale children [ DEF Block Shape { appearance Appearance { material Material { diffuseColor IS _SideColor } } geometry Box { size IS _Blocksize } } Transform { translation -2.875 0 -3 rotation 0 1 0 1.57 children USE Block } Transform { translation 2.875 0 -3 rotation 0 1 0 1.57 children USE Block } Transform { translation 0 0 -6 children USE Block } Transform { translation 0 -.125 -3 children [ Shape { appearance Appearance { material Material { diffuseColor IS _FloorColor } } geometry Box { size 6 .01 6 } } Transform { children [ Shape { appearance Appearance { material Material { diffuseColor 0 0 0 } } geometry IndexedLineSet { coord Coordinate { point [ -.75 .05 3, -.75 .05 2.5, .75 .05 2.5, .75 .05 3, ] } coordIndex [ 0 1 2 3 ] } } ] } Transform { children [ Shape { appearance Appearance { material Material { diffuseColor 0 0 1 } } geometry IndexedLineSet { coord Coordinate { point [ -.75 .05 -3, -.75 .05 -2.5, .75 .05 -2.5, .75 .05 -3, ] } coordIndex [ 0 1 2 3 ] } } ] } Transform { children [ Shape { appearance Appearance { material Material { diffuseColor 0 0 1 } } geometry IndexedLineSet { coord Coordinate { point [ -3 .05 0, 3 .05 0, ] } coordIndex [ 0 1 ] } } ] } ] } ] } } ## ---- End Of theField Prototype ---- ## PROTO Title [ exposedField SFColor _TextColor 1 1 1 field SFVec3f _TitleTranslation 0 3 -4.5 field SFRotation _TitleRotation 1 0 0 -1.25 ] { Transform { translation IS _TitleTranslation rotation IS _TitleRotation children [ ## ---- Timer For The ColorInterpolator ---- ## DEF Timer TimeSensor { cycleInterval 5 loop TRUE } ## ---- The Interpolator For Changing the colours ---- ## ## ---- for The Text ---- ## DEF ColInter ColorInterpolator { key [ 0 .33 .66 1 ] keyValue [ 1 0 0 0 1 0 0 0 1 1 0 0 ] } Shape { appearance Appearance { material DEF NewCol Material { diffuseColor IS _TextColor } } geometry Text { string [ ".: VRML AIR HOCKEY :." ] fontStyle FontStyle { justify "MIDDLE" style "BOLD" size .75 } } } ] #Root } #Root ## ---- Route Time Change From the Timer To The Interpolator ---- ## ROUTE Timer.fraction_changed TO ColInter.set_fraction ## ---- Route The New Value From The Interpolator to the Diffusecolor ---- ## ROUTE ColInter.value_changed TO NewCol.set_diffuseColor } ## ---- Instantiate The Objects ---- ## ## ---- I have used the Billboard node, incase i want user interaction ---- ## ## ---- later if i add somthing new toi the game, If the user moves ---- ## ## ---- or rotates away from the field, the field will always be facing ---- ## ## ---- the user so they will alwasy have the best viewing point. ---- ## Billboard { children [ ## ---- Turn Off Cosmo's Control Bar. I Want No User Interaction Here ---- ## NavigationInfo { type "NONE" } ## ---- Define The ViewPoint On Entry ---- ## Viewpoint { position 0 8 1.75 orientation 1 0 0 -.99 description "Entry" } ## ---- Draw The All the Text On The Screen ---- ## Title { _TextColor 1 .2 0 } ## ---- Draw The Field -- ## theField { _Scale 1 1 1 _SideColor 0 0 1 _FloorColor 1 1 1 } ## ---- Draw The Puck And The Paddels To Play With ---- ## GamingObject { _TranslationPaddel 0 0 -.5 _Scale 1 .5 1 _PaddelColor 0 0 0 _TranslationPuck 0 0 -3 _PuckColor 1 0 0 } ] }