© opyright ryecatcher Intellectual Property 2023
javascript source code for Baseball Vidgame Pitch Selection Functions
// INITIALIZE GLOBAL VARIABLES ==================================================================================================================================================================
let velocity = 10; //this is the y-axis amount by which the baseball is incremented during each interval during its motion towards the strike zone ie. y = y + velocity
//let speed = 15; this was the intial amount used during game development but determined 10 was better
let pitchTimer = null; //this variable is used in clearInterval function to stop the setInterval function that is used to create baseball motion towards the strike zone
let y = 50; //this is the initial y-axis value position of the ball at the pitcher's release point ie. 50 pixels from the top
let angle = null; //initialize variable representing the angle used to determine trajectory of ball from ball origin at pitcher release point
let toa = null; //derived from SOH CAH TOA & used to help calculate pitch ball angle to plate ie. toa=opposite/adjacent
let opposite = 30; //represents value of deviation distance from centre of strike zone along x axis used to calculate angle to plate
let adjacent = 520; //represents y axis value of distance from pitcher release to strike zone ie. 570px used to calculate angle to plate
/* angle
/|
hypotenuse / | adjacent side ie. in this case is distance from pitcher release point hypotenuse side will represent trajectory of ball from pitcher release
side / | to strike zone point to the pre-selected deviation distance from centre of stike zone
/___|
opposite side ie. in this case is the deviation distance the ball will end up from center of strike zone
*/
//let pitch_selection = [fastball, heater, changeup, curveball, slider, screwball, knuckleball];
let pitch_type = "curveball"; //initialize variable representing pitch type
//game level of difficulty; determines how quickly time intervals between pitch ball increments; essentially velocity
let difficulty_level = "beginner"; //initialize variable used to represent game difficulty level selected by player at beginning of game
let beginner = 25; // 40 initialize variable value used to represent beginner game difficulty level; will correspond to pitch velocity ie. slowest
let intermediate = 20;
let advanced = 15; // 25
let expert = 10; // 20
//let pro = 10; // 20
let interval_frequency = 30; // initialize variable used in setInterval function used to simulate velocity of pitches; will be set to value of beginner constant or intermediate const etc
let ball_strike = null; //initialize variable to indicate whether pitch trajectory will cross plate or miss plate
let plate_location_left_right = null; //initialize variable to indicate whether pitch trajectory will deviate to left or right from centre of strike zone
let plate_location_amount = 10; //initialize variable to indicate distance pitch trajectory will deviate to left or right from centre of strike zone
// console.log("offset left value: " + document.querySelector("#strike_zone").offsetLeft); //test only remove
// console.log("offset width value: " + document.querySelector("#strike_zone").offsetWidth); //test only remove
//console.log("width value: " + document.querySelector("#strike_zone").style.width);
let sz_left = document.querySelector("#strike_zone").offsetLeft; //initialize variable deriving value for left edge of strike zone; used to determine proximity ball & strikezone
let sz_right = sz_left + document.querySelector("#strike_zone").offsetWidth; //initialize variable deriving right edge of strike zone etc.
let sz_top = document.querySelector("#strike_zone").offsetTop; //top edge of strike zone
let sz_bottom = sz_top + document.querySelector("#strike_zone").offsetHeight; //bottom edge
console.log("sz_top: " + sz_top);
console.log("sz_bottom: " + sz_bottom);
let bb_left = document.querySelector("#baseball").offsetLeft; //initialize variable derived from x-axis position of left edge of baseball; changes during flight of ball...
let bb_right = bb_left + document.querySelector("#baseball").offsetWidth; //ie. right edge ...used to compare relative proximities of ball and strike zone
let bb_top = document.querySelector("#baseball").offsetTop; //initialize variable derived from y-axis position of top edge of baseball; changes during flight of ball...
let bb_bottom = bb_top + document.querySelector("#baseball").offsetHeight; //ie. bottom edge ...used to compare relative proximities of ball and strike zone
let sz_center = (sz_left + sz_right) / 2; //intialize variable value derived to represent centre of strike zone; further used to derive the following constants...
let sz_sweetspot_left = sz_center - 5; //variable representing left edge of inner core of strike zone; used to help determine outcome of swing contact (ie.best result in this case)
let sz_sweetspot_right = sz_center + 5;
let sz_heart_left = sz_center - 10; //variable representing left edge of secondary core of strike zone; used to help determine outcome of swing contact (ie.second best result)
let sz_heart_right = sz_center + 10;
let hit_range = null;
let vertical_strike_zone = null;
let horizontal_strike_zone = null;
let inside_strike_zone = null;
if ((bb_right >= sz_left && bb_right <= sz_right) || (bb_left >= sz_left && bb_left <= sz_right)) {
vertical_strike_zone = true;
}
if ((bb_top >= sz_bottom && bb_top <= sz_top) || (bb_bottom >= sz_bottom && bb_bottom <= sz_top)) {
horizontal_strike_zone = true;
}
if (vertical_strike_zone === true && horizontal_strike_zone === true) {
inside_strike_zone = true;
}
let knuckleball_break_direction_generator = null;
let knuckleball_break_amount = null;
let break_direction = null;
//EVENT LISTENERS FOR READY & SWING BUTTONS: =================================================================================================
document.querySelector("#ready").addEventListener("mousedown", ready);
document.querySelector("#swing").addEventListener("touchstart", swing); //TOUCHSCREEN >>>>>>>>>>>>>>>>>
document.querySelector("#swing").addEventListener("mousedown", swing);
// ============================================================================================================================================
// EVENT LISTENER FOR DISPLAYING FIELD =======================================================================================================
//document.querySelector("#field_button").addEventListener("click", switch_fields);
//document.querySelector("#field_button").addEventListener("click", switch_fields);
document.querySelector("#field_button").addEventListener("click", switch_fields_intermediary_func);
//document.querySelector("#field_button").addEventListener("click", function () { switch_fields() });
// =============================================================================================================================================
angle_calc();
function switch_fields_intermediary_func() {
switch_fields();
}
// DEVIATION_DISTANCE FUNCTION =================================================================================================================================================================
// utility function used to (slightly weighted) randomly pre-determine the deviation distance (plate_location_amount variable) of the ball from the center of the strike zone; called by throw_pitch() func
function deviation_distance() {
//console.log("DEVIATION DISTANCE FUNCTION!! ball vs strike: " + ball_strike);
if (ball_strike <= 50) { // ie. 50% chance ie. definitely inside strike zone
plate_location_amount = Math.round(Math.random() * 20);
//if (plate_location_amount === 0) { plate_location_amount = 0.1 }
}
else if (ball_strike >= 51 && ball_strike <= 75) { // initially between 51 and 80 (25% chance) ie. changed to 51 to 75 (25%)
plate_location_amount = Math.round(Math.random() * 10) + 20;
}
else if (ball_strike >= 76) { // initially greater than 81 (25% chance) definite ball outside strikezone ie. changed to 76 25%
plate_location_amount = Math.round(Math.random() * 10) + 30;
}
//angle_calc(); commented out because located elsewhere therefore redundant
// console.log("************** HUMAN PITCHING plate_location_amount: " + plate_location_amount);
}
// ANGLE_CALC FUNCTION ==============================================================================================================================================================
// utility function used to derive angle of trajectory from pitcher release point to pre-determined deviation distance from centre of strike zone (ie. plate_location_amount) see diagram below
function angle_calc() {
//plate_location_amount = 40; //diagnostic only remove!!!!
opposite = plate_location_amount; //represents deviation distance from centre of strike zone
console.log("plate location amount: " + plate_location_amount);
console.log("opposite: " + opposite);
toa = opposite / adjacent; //calculate trignometric TOA TAN value = opposite side / adjacent side
angle = Math.atan(toa) * 180 / Math.PI; //use arctan to get angle value then convert to radians for use in javascript -- NOTE: angle variable represents degrees!!!!
console.log("************** HUMAN PITCHING angle calculation: " + angle);
// document.querySelector("#angle").textContent = angle; //angle in degrees NOTE:this was displayed for diagnostic purposes only
// let opposite2 = Math.tan(angle * Math.PI / 180) * 570; //NOTE:this was calculated for diagnostic purposes only
// document.querySelector("#opposite").textContent = opposite2 + " ** " + plate_location_left_right; //length of opposite side in pixels NOTE:this was displayed for diagnostic purposes only
}
/* angle
/|
hypotenuse / | adjacent side ie. in this case is distance from pitcher release point hypotenuse side will represent trajectory of ball from pitcher release
side / | to strike zone along y-axis point to the pre-selected deviation distance from centre of stike zone
/___|
opposite side ie. in this case is the deviation distance the ball will end up from center of strike zone along x-axis
*/
// PITCH_SELECTION FUNCTION ===============================================================================================================================================================
// utility function used to randomly select and return type of pitch the computer will throw; is called by the throw_pitch() function
function pitch_selection() {
let pitch_range = Math.floor(Math.random() * 100) + 1; //set variable assigned a randomly generated number between 1 and 100
// console.log("pitch selection!!!!");
// pitch_range = 40; //diagnostic
// console.log("pitch range: " + pitch_range); //diagnostic
if (pitch_range <= 50) { // 50% chance fastball will be selected
//console.log("in switch fastball!!");
pitch_type = "fastball";
}
else if (pitch_range >= 51 && pitch_range <= 55) { // 5% chance
pitch_type = "heater2";
}
else if (pitch_range >= 56 && pitch_range <= 65) { // 10% chance
pitch_type = "changeup";
}
else if (pitch_range >= 66 && pitch_range <= 70) { // 5% chance
pitch_type = "knuckleball";
}
else if (pitch_range >= 71 && pitch_range <= 85) { // 15% chance
pitch_type = "curveball";
}
else if (pitch_range >= 86 && pitch_range <= 95) { // 10% chance
pitch_type = "slider";
}
else if (pitch_range >= 96) { // 5% chance
pitch_type = "screwball";
}
return pitch_type; //returns type of pitch
}
// READY FUNCTION =======================================================================================================================================================================
// this is the event listener function for the READY button which user presses to indicate is ready to recieve pitch; it sets the pitch delivery process in motion...
function ready() {
if (start_inning === true) {
strikezone_3d_hide() //hide 3d strikezone because is distracting and already served purpose as reminder of set up
}
document.querySelector("#ready").removeEventListener("mousedown", ready); //remove event listeners during initiation to prevent unintended multiple clicks & resultant problems
document.querySelector("#swing").removeEventListener("touchstart", swing); //TOUCHSCREEN >>>>>>>>>>>>>>>>
document.querySelector("#swing").removeEventListener("mousedown", swing);
inside_strike_zone = false; // resetting value
// document.querySelector("#strike_ball").textContent = ""; //diagnostic strike hit indicator
y = 50; //reset y-axis variable for ball at pitcher release point ie. 50px from top of pitching field container
document.querySelector("#baseball").style.display = "none"; // hide ball from previous frozen position
document.querySelector("#ready").style.display = "none"; // hide buttons during initiation to prevent unintended multiple clicks & resultant problems
document.querySelector("#swing").style.display = "none";
document.querySelector("#swing_called_indicator").textContent = ""; // clear previous data display
document.querySelector("#strike_ball_indicator").textContent = ""
// document.querySelector("#beginning_inning_indicator").textContent = "";
document.querySelector("#beginning_inning_indicator_container").style.display = "none"; //hide beginning inning indicator
document.querySelector("#instructions_ready").style.display = "none"; //hide beginning inning indicator
document.querySelector("#instructions_swing").style.display = "none"; //hide beginning inning indicator
//pitchTimer = window.setInterval(floatUp, 20);
//window.setTimeout(throw_pitch, 1000); //sets one second pause to allow batter to get ready before transferring to throw_pitch function for main execution of pitch delivery
window.setTimeout(arms_head_2, 100); //initiate display of pitcher throwing motion
}
// THROW_PITCH FUNCTION =========================================================================================================================================================================
// important function used primarily to redirect to the applicable type of pitch function that will display the ball trajectory and decide strike zone overlap
// if computer is pitching, choices will be decided randomly; if human is pitching will direct to desired choice
function throw_pitch() {
if (computer_pitching === true) {
deviation_distance(); //calls this func to randomly set the deviation distance variable from center of strike zone
angle_calc(); //calls this func to derive the angle of trajectory from pitcher release point to deviation distance from center of strike zone
}
document.querySelector("#baseball").style.display = "block";
// document.querySelector("#beginning_inning_indicator").textContent = "";
document.querySelector("#beginning_inning_indicator_container").style.display = "none"; //hide beginning inning indicator
//DECIDE IF PITCH WILL CROSS THE PLATE OR NOT:
if (computer_pitching === true) {
ball_strike = Math.floor(Math.random() * 100) + 1; //66% strike possibility and 34% ball possibility
}
//DECIDE WHICH SIDE OF PLATE PITCH WILL DEVIATE TO:
if (computer_pitching === true) {
if (Math.floor(Math.random() * 10) < 5) {
plate_location_left_right = -1 //will deviate to left side of plate
}
else { plate_location_left_right = 1 } //will deviate to right side of plate
}
// opposite = opposite * plate_location_left_right;
//DECIDE TYPE OF PITCH:
if (computer_pitching === true) {
pitch_type = pitch_selection(); //calls pitch_selection() which returns weighted random pitch type choice
} else {
pitch_type = human_pitch_selection; //reassigns to variable type of pitch selected by human player
random_contact_line = Math.floor(Math.random() * 40) + sz_top; //variable used to determine where computer swing contact occurs inside strike zone
outside_contact_percent = Math.floor(Math.random() * 100) + 1; //variable used to determine whether computer swing occurs outside the strike zone
swing_inside_sz_percent = Math.floor(Math.random() * 100) + 1; //variable used to determine whether computer swing occurs inside the strike zone
}
//pitch_type = "fastball"; //DIAGNOSTIC!!!!!! ****************************************************************************
// document.querySelector("#pitch_type").textContent = pitch_type; //pitch type display for diagnostic purposes ---- will be removed
//GAME DIFFICULTY LEVEL:
difficulty_level = selected_difficulty_level; //chosen by the user in the intro page
if (difficulty_level === "beginner") { interval_frequency = beginner; } //used to set the pitch interval frequency; ie.velocity of pitch...
else if (difficulty_level === "intermediate") { interval_frequency = intermediate; } // ...game difficulty level due primarily to velocity of pitches...
else if (difficulty_level === "advanced") { interval_frequency = advanced; } // ...ie. faster is harder to hit etc.
else if (difficulty_level === "expert") { interval_frequency = expert; }
//else if (difficulty_level === "pro") { interval_frequency = pro; }
strike_indicator = false; //reset for next pitch
ball_indicator = false;
//CALL APPLICABLE PITCH TYPE FUNCTION TO DISPLAY AND EXECUTE:
switch (pitch_type) {
case "fastball":
if (computer_pitching === true) {
document.querySelector("#swing").style.display = "block"; //restore swing button display to allow human player to "swing" at ball
document.querySelector("#swing").addEventListener("touchstart", swing); //TOUCHSCREEN >>>>>>>>>>>>>>>>
document.querySelector("#swing").addEventListener("mousedown", swing); //restore swing button event listener to allow human player to "swing" at ball
pitchTimer = window.setInterval(fastball, interval_frequency); //to display computer fastball pitch repeatedly call fastball() at interval length "interval_frequency"
} else {
pitchTimer = window.setInterval(human_fastball, interval_frequency); //to display human fastball pitch repeatedly call human_fastball() at interval length "interval_frequency"
}
break;
case "heater2":
if (computer_pitching === true) {
document.querySelector("#swing").style.display = "block";
document.querySelector("#swing").addEventListener("touchstart", swing); //TOUCHSCREEN >>>>>>>>>>>>>>>>
document.querySelector("#swing").addEventListener("mousedown", swing);
pitchTimer = window.setInterval(fastball, interval_frequency - interval_frequency * .1); //note: interval frequency is set 10% less; therefore heater pitch velocity is 10% faster...
} else { // ...than a fastball which is the pitch velocity baseline
pitchTimer = window.setInterval(human_fastball, interval_frequency - interval_frequency * .1);
}
break;
case "changeup":
if (computer_pitching === true) {
document.querySelector("#swing").style.display = "block";
document.querySelector("#swing").addEventListener("touchstart", swing); //TOUCHSCREEN >>>>>>>>>>>>>>>>
document.querySelector("#swing").addEventListener("mousedown", swing);
pitchTimer = window.setInterval(fastball, interval_frequency + interval_frequency * .1); //note: interval frequency is set 10% more; therefore changeup pitch velocity is 10% slower...
} else { // ...than a fastball which is the pitch velocity baseline
pitchTimer = window.setInterval(human_fastball, interval_frequency + interval_frequency * .1);
}
break;
case "knuckleball":
knuckleball_break_amount = Math.random() * 4 + 2; //randomly set the amount the knuckleball will break beyond preset trajectory
knuckleball_break_direction_generator = Math.random() * 10; //randomly determine whether knucklewall will break in right or left direction
if (knuckleball_break_direction_generator < 5) {
break_direction = "rright";
} else { break_direction = "lleft"; }
if (computer_pitching === true) {
document.querySelector("#swing").style.display = "block";
document.querySelector("#swing").addEventListener("touchstart", swing); //TOUCHSCREEN >>>>>>>>>>>>>>>>
document.querySelector("#swing").addEventListener("mousedown", swing);
pitchTimer = window.setInterval(knuckleball, interval_frequency + interval_frequency * .2); //note: knuckleball velocity is 20% slower than fastball velocity baseline
} else {
document.querySelector("#baseball").style.opacity = "0"; //makes ball invisible because call to pre_curveball() is just to set the x-axis and y-axis values for ball
x_curveball_array = []; //reset array to contain x-axis values for displaying ball & determining strike zone overlap
y_curveball_array = []; //reset array to contain y-axis values...
human_knuckleball_interval = interval_frequency + interval_frequency * .2; //note: interval frequency for display is set 20% more; therefore knuckleball pitch velocity is 20% slower...
pitchTimer = window.setInterval(pre_knuckleball, 1); //interval calls to pre_knuckleball() are very high speed because its just to set the x-axis and y-axis values for ball...
//...pre_knuckleball() will call post_knuckleball() where ball will be displayed and strike zone overlap will be determined
}
break;
case "curveball":
curveball_break_amount = 1.5 + Math.random() * 1.5; //randomly set the amount the curveball will break beyond preset trajectory
if (computer_pitching === true) {
document.querySelector("#swing").style.display = "block";
document.querySelector("#swing").addEventListener("touchstart", swing); //TOUCHSCREEN >>>>>>>>>>>>>>>>
document.querySelector("#swing").addEventListener("mousedown", swing);
pitchTimer = window.setInterval(curveball, interval_frequency + interval_frequency * .1); //note: interval frequency is set 10% more; therefore changeup pitch velocity is 10% slower
} else {
document.querySelector("#baseball").style.opacity = "0"; //makes ball invisible because call to pre_curveball() is just to set the x-axis and y-axis values for ball
x_curveball_array.length = 0; //same as x_curveball_array = []; //reset array to contain x-axis values for displaying ball & determining strike zone overlap
y_curveball_array.length = 0; //same as y_curveball_array = []; //reset array to contain y-axis values...
human_curveball_interval = interval_frequency + interval_frequency * .1; //note: interval frequency for display is set 10% more; therefore curveball pitch velocity is 10% slower...
//...this will be used in post_curveball() where ball will be displayed
pitchTimer = window.setInterval(pre_curveball, 1); //interval calls to pre_curveball() are very high speed because its just to set the x-axis and y-axis values for ball...
//...pre_curveball() will call post_curveball() where ball will be displayed and strike zone overlap will be determined
}
break;
case "slider":
curveball_break_amount = 1.5 + Math.random() * 1.5;
// 20
if (computer_pitching === true) {
document.querySelector("#swing").style.display = "block";
document.querySelector("#swing").addEventListener("touchstart", swing); //TOUCHSCREEN >>>>>>>>>>>>>>>>
document.querySelector("#swing").addEventListener("mousedown", swing);
pitchTimer = window.setInterval(curveball, interval_frequency + interval_frequency * .05); //note: interval frequency is set 5% more; therefore changeup slider velocity is 5% slower
} else {
document.querySelector("#baseball").style.opacity = "0";
x_curveball_array = [];
y_curveball_array = [];
human_curveball_interval = interval_frequency + interval_frequency * .05; //note: interval frequency for display is set 5% more; therefore slider pitch velocity is 5% slower...
pitchTimer = window.setInterval(pre_curveball, 1);
}
break;
case "screwball":
curveball_break_amount = 1.5 + Math.random() * 1.5;
if (computer_pitching === true) {
document.querySelector("#swing").style.display = "block";
document.querySelector("#swing").addEventListener("touchstart", swing); //TOUCHSCREEN >>>>>>>>>>>>>>>>
document.querySelector("#swing").addEventListener("mousedown", swing);
pitchTimer = window.setInterval(curveball, interval_frequency + interval_frequency * .1); //note: interval frequency for display is set 10% more; therefore screwball pitch velocity is 10% slower
} else {
document.querySelector("#baseball").style.opacity = "0";
x_curveball_array = [];
y_curveball_array = [];
human_curveball_interval = interval_frequency + interval_frequency * .1; //note: interval frequency for display is set 10% more; therefore screwball pitch velocity is 10% slower...
pitchTimer = window.setInterval(pre_curveball, 1);
}
break;
}
} // end of throw_pitch() function
function heater_delay2() { //this function not in use
document.querySelector("#ready").style.display = "block";
console.log("should be going here");
}