private ThryBP_Glass GetClosestGlassToPredictedTableCollision(Vector3 prediction) { //Get Cup closest to that point ThryBP_Glass aimedCup = null; float closestDistance = float.MaxValue; for (int p = 0; p < _mainScript.playerCountSlider.local_float; p++) { float d = 0; foreach (ThryBP_Glass cup in _mainScript.players[p].cups.activeGlassesGameObjects) { if (cup == null) { continue; } if (cup.player.playerIndex == currentPlayer) { continue; } d = Vector3.Distance(cup.transform.position, prediction); if (d < closestDistance) { closestDistance = d; aimedCup = cup; } } } return(aimedCup); }
void DoRimming() { if (rimming < RIMMING_TOTAL_AGULAR_ROTATION) { ThryBP_Glass cup = _mainScript.GetCup(state[1], state[2], state[3]); if (Utilities.IsValid(cup)) { rimming += RIMMING_SPEED * Time.deltaTime; float inside = 0.9f - rimming / RIMMING_TOTAL_AGULAR_ROTATION * 0.15f; float downwards = 1 - rimming / RIMMING_TOTAL_AGULAR_ROTATION * 0.3f; float angle = (rimming - Mathf.Pow(rimming * 0.009f, 2)) / cup.circumfrence * 0.4f; transform.position = cup.transform.position + Vector3.up * (cup.GetBounds().size.y *downwards) + Quaternion.Euler(0, angle, 0) * Vector3.forward * (cup.radius * cup.transform.lossyScale.x * inside - _radius); } } else { ThryBP_Glass cup = _mainScript.GetCup(state[1], state[2], state[3]); if (Utilities.IsValid(cup)) { cup.colliderInside.SetActive(true); cup.colliderForThrow.enabled = false; _rigidbody.velocity = Quaternion.Euler(0, 90 + rimming, 0) * Vector3.forward * 0.3f; //in circle _rigidbody.velocity += Quaternion.Euler(0, rimming + 180, 0) * Vector3.forward * 0.1f; //inwards _rigidbody.velocity += Vector3.down * 0.1f; //downwards SetDynamic(); localState = STATE_IN_CUP; stateStartTime = Time.time; _TriggerSplash(); _pickup.pickupable = !autoRespawnBallAfterCupHit; } } }
private Vector3 DoAIVectoring(Vector3 velocity, Vector3 position, float skill) { if (skill == 0) { return(velocity); } //Get Point where ball will hit table Vector3 predictionTableHit = PredictTableHit(velocity, position, tableHeight); ThryBP_Glass cup = GetClosestGlassToPredictedTableCollision(predictionTableHit); if (cup == null) { return(velocity); } Vector3 cupOpening = cup.transform.position + Vector3.up * cup.GetBounds().size.y; Vector3 optimalVector = OptimalVectorChangeStrength(velocity, position, cup); float lerping = Random.Range(0f, 1f); if (lerping < skill) { lerping = 1; } velocity = Vector3.Lerp(velocity, optimalVector, lerping); return(velocity); }
//Instanciating public void InstanciateGlass(int row, int collum, int index) { float relativeX = (float)collum - MAX_ROWS; Vector3 position = new Vector3(relativeX * glass.radius * scale, 0, row * glass.diameter * scale); GameObject instance = VRCInstantiate(glass.gameObject); instance.transform.SetParent(anchors[anchor_id]); instance.transform.localPosition = position + position_offset; instance.transform.localRotation = Quaternion.identity; instance.transform.localScale = Vector3.one * scale; instance.SetActive(true); ThryBP_Glass thryglass = instance.GetComponent <ThryBP_Glass>(); thryglass.row = row; thryglass.collum = collum; thryglass.player = _player; thryglass.anchor_id = anchor_id; thryglass.position_offset = position_offset; thryglass.radius = glass.radius; thryglass.diameter = glass.diameter; thryglass.circumfrence = glass.circumfrence; activeGlassesGameObjects[index] = thryglass; SetColor(thryglass, index); }
//=========Collision Code====== private void ResetLastCupsColliders() { ThryBP_Glass cup = _mainScript.GetCup(state[1], state[2], state[3]); if (Utilities.IsValid(cup)) { cup.colliderForThrow.enabled = true; cup.colliderInside.SetActive(false); } }
private void BallGlassCollision(Collision collision, ThryBP_Glass hitGlass) { Bounds b = hitGlass.GetBounds(); bool isCollisionOnTop = (b.max.y < transform.position.y); SetDynamic(); if (isCollisionOnTop) { Vector3 p1 = transform.position; p1.y = 0; Vector3 p2 = hitGlass.transform.position; p2.y = 0; float distanceFromCenter = Vector3.Distance(p1, p2) / ((b.extents.x + b.extents.z) / 2); if (distanceFromCenter < COLLISION_MAXIMUM_DISTANCE_FROM_CENTER) { float angle = Vector3.Angle(_lastvelocies[_lastvelociesHead], Vector3.down); //bool tripOnEdge = distanceFromCenter > Random.Range(0, 0.85f); bool tripOnEdge = distanceFromCenter > Random.Range(0.4f, 0.7f) && angle > Random.Range(45, 80); //if it lands really flat chances are higher for it to ride edge if (tripOnEdge) { SetState(STATE_RIMING); state[1] = (byte)hitGlass.player.playerIndex; state[2] = (byte)hitGlass.row; state[3] = (byte)hitGlass.collum; rimming = Vector3.Angle(hitGlass.transform.rotation * Vector3.forward, p2 - p1); if ((p2 - p1).x > 0) { rimming = 360 - rimming; } rimming = rimming % 360; state[4] = (byte)(rimming / 2); state[5] = (byte)(distanceFromCenter * 100); } else { hitGlass.colliderForThrow.enabled = false; hitGlass.colliderInside.SetActive(true); _pickup.pickupable = !autoRespawnBallAfterCupHit; SetState(STATE_IN_CUP); state[1] = (byte)hitGlass.player.playerIndex; state[2] = (byte)hitGlass.row; state[3] = (byte)hitGlass.collum; _TriggerSplash(); _rigidbody.velocity = Vector3.down * startVelocityLocal.magnitude; } RequestSerialization(); } } }
//=======Array syncing======== public void SetColor(ThryBP_Glass g, int index) { if (_player.randomColor) { UnityEngine.Random.InitState(index); g.SetColor(new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value)); } else { g.SetColor(_player.playerColor); } }
void DoInCup() { ThryBP_Glass cup = _mainScript.GetCup(state[1], state[2], state[3]); if (Utilities.IsValid(cup)) { //if ball is not in cup teleport ball in cup Collider c = cup.colliderForThrow; c.enabled = true; Vector3 cPoint = c.ClosestPoint(transform.position); c.enabled = false; Bounds b = cup.GetBounds(); b.size = b.size += Vector3.up; if (Vector3.Distance(cPoint, transform.position) > 0.01f && ((_rigidbody.velocity.sqrMagnitude == 0) || (b.Contains(transform.position) == false))) { //Debug.Log($"cPoint: {cPoint.ToString("F3")} point: {transform.position.ToString("F3")}"); //Debug.Log($"[ThryBP] Teleported ball into cup ({state[1]},{state[2]},{state[3]})"); transform.position = cup.GetBounds().center; } else if (Networking.IsOwner(gameObject)) { if (_mainScript.gamemode == 0) { if (Time.time - stateStartTime > (autoRespawnBallAfterCupHit ? 2 : 20)) { _mainScript.CountCupHit(state[1], state[2], state[3], currentPlayer, state[0] == STATE_RIMING ? 1 : 0); _mainScript.RemoveCup(state[1], state[2], state[3], currentPlayer); Respawn(); } } else if (_mainScript.gamemode == 1) { if (Time.time - stateStartTime > 1) { _mainScript.CountCupHit(state[1], state[2], state[3], currentPlayer, state[0] == STATE_RIMING ? 1 : 0); _mainScript.RemoveCup(state[1], state[2], state[3], currentPlayer); Respawn(); } } else if (_mainScript.gamemode == 2) { if (Time.time - stateStartTime > 3) { _mainScript.CountCupHit(state[1], state[2], state[3], currentPlayer, state[0] == STATE_RIMING ? 1 : 0); Respawn(); } } } } }
private void OnCollisionEnter(Collision collision) { if (collision.collider == null || collision.collider.gameObject == null) { return; } bool hasHitGlass = collision.collider.gameObject.GetComponent <ThryBP_Glass>() != null; if (hasHitGlass) { PlayAudio(audio_collision_glass, startVelocityLocal.sqrMagnitude / 10); } else { PlayAudio(audio_collision_table, startVelocityLocal.sqrMagnitude / 10); } startPositionLocal = transform.position; startVelocityLocal = Vector3.Reflect(VelocityAtTime(startVelocityLocal, Time.time - physicsSimulationStartTime), Vector3.up) * BOUND_DRAG; physicsSimulationStartTime = Time.time; if (Networking.IsOwner(gameObject)) { if (state[0] == STATE_FYING) { if (hasHitGlass) { ThryBP_Glass hitGlass = collision.collider.gameObject.GetComponent <ThryBP_Glass>(); //check if collision with own glass and if friendly fire is turned on if (_mainScript.AllowCollision(currentPlayer, hitGlass.player)) { BallGlassCollision(collision, hitGlass); } } //none beer pong object => miss else if (collision.collider.gameObject.name.StartsWith("[ThryBP]") == false) { Debug.Log("[ThryBP] Ball hit non game object. Respawning for other team."); NextTeam(); Respawn(); } } } }
private Vector3 DoAimbotVectoring(Vector3 velocity, Vector3 position, float strength) { if (strength == 0) { return(velocity); } //Get Point where ball will hit table Vector3 predictionTableHit = PredictTableHit(velocity, position, tableHeight); ThryBP_Glass cup = GetClosestGlassToPredictedTableCollision(predictionTableHit); if (cup == null) { return(velocity); } Vector3 cupOpening = cup.transform.position + Vector3.up * cup.GetBounds().size.y; Vector3 hitOnCupPlane = PredictTableHit(velocity, position, cupOpening.y); if (Vector3.Distance(cupOpening, hitOnCupPlane) > strength) { return(velocity); } return(OptimalVectorChangeStrength(velocity, position, cup)); }
private Vector3 OptimalVectorChangeAngle(Vector3 velocity, Vector3 position, float tableHeight, ThryBP_Glass aimedCup) { //Calculate trajectory to that cup Vector3 horizonzalDistance = aimedCup.transform.position - position; horizonzalDistance.y = 0; //https://www.youtube.com/watch?v=bqYtNrhdDAY&ab_channel=MichelvanBiezen //https://www.youtube.com/watch?v=pQ23Eb-bXvQ&ab_channel=MichelvanBiezen float g = -Physics.gravity.y; float v2 = velocity.sqrMagnitude; float x = horizonzalDistance.magnitude; float h = position.y - (tableHeight + aimedCup.GetBounds().size.y); float phi = Mathf.Atan(x / h); float theta = (Mathf.Acos(((g * x * x / v2) - h) / Mathf.Sqrt(h * h + x * x)) + phi) / 2; Vector3 newVel = (horizonzalDistance.normalized * Mathf.Cos(theta) + Vector3.up * Mathf.Sin(theta)) * velocity.magnitude; if (float.IsNaN(theta)) { //cant reacht cup with current velocity //just aim in it's direction instead Vector3 horizontalVel = velocity; horizontalVel.y = 0; newVel = horizonzalDistance.normalized * horizontalVel.magnitude; newVel.y = velocity.y; } return(newVel); }
private Vector3 OptimalVectorChangeStrength(Vector3 velocity, Vector3 position, ThryBP_Glass cup) { Vector3 cupOpening = cup.transform.position + Vector3.up * cup.GetBounds().size.y; Vector3 horizonzalVector = cupOpening - position; horizonzalVector.y = 0; Vector3 horizonzalVelocity = velocity; horizonzalVelocity.y = 0; //https://www.youtube.com/watch?v=mOYJKv22qeQ&list=PLX2gX-ftPVXUUlf-9Eo_6ut4kP6wKaSWh&index=7&ab_channel=MichelvanBiezen // d = v0 * cos(w) * t // => t = d / (v0 * cos(w)) // y = y0 + v0 * sin(w) * t - 0.5 * g * t2 // y = y0 + v0 * sin(w) * ( d / (v0 * cos(w)) ) - 0.5 * g * ( d / (v0 * cos(w)) )2 // y = y0 + tan(w) * d - 0.5 * g * ( d / (v0 * cos(w)) )2 // y0 - y + tan(w) * d = 0.5 * g * ( d / (v0 * cos(w)) )2 // 2(y0 - y + tan(w) * d) / g = ( d / (v0 * cos(w)) )2 // sqrt( 2(y0 - y + tan(w) * d) / g) = d / (v0 * cos(w)) // v0 * cos(w) = d / sqrt( 2(y0 - y + tan(w) * d) / g) // v0 = d / sqrt( 2(y0 - y + tan(w) * d) / g) / cos(w) float d = horizonzalVector.magnitude; float y0 = position.y; float y = cupOpening.y; float w = Mathf.Deg2Rad * Vector3.Angle(horizonzalVelocity, velocity); float g = -Physics.gravity.y; float v0 = d / Mathf.Sqrt(2 * (y0 - y + Mathf.Tan(w) * d) / g) / Mathf.Cos(w); Vector3 newDirection = horizonzalVector.normalized * horizonzalVelocity.magnitude; newDirection.y = velocity.y; return(newDirection.normalized * v0); }
public override void OnDeserialization() { _pickup.pickupable = state[0] == STATE_IDLE || (state[0] == STATE_IN_CUP && !autoRespawnBallAfterCupHit); SetColor(); if (state[0] == STATE_IDLE) { SetStatic(); transform.position = start_position; transform.rotation = start_rotation; startVelocityLocal = Vector3.zero; } else if (state[0] == STATE_IN_HAND) { SetStatic(); throwIndicator.gameObject.SetActive(false); } else if (state[0] == STATE_LOCKED) { transform.position = start_position; transform.rotation = start_rotation; throwIndicator.SetPositionAndRotation(transform.position, transform.rotation); throwIndicator.gameObject.SetActive(true); } else if (state[0] == STATE_FYING) { transform.position = start_position; transform.rotation = start_rotation; startPositionLocal = start_position; startVelocityLocal = start_velocity; physicsSimulationStartTime = Time.time; SetStaticCollisions(); throwIndicator.gameObject.SetActive(false); } else if (state[0] == STATE_RIMING) { rimming = state[4] * 2; } else if (state[0] == STATE_IN_CUP) { ThryBP_Glass cup = _mainScript.GetCup(state[1], state[2], state[3]); if (Utilities.IsValid(cup)) { cup.colliderForThrow.enabled = false; cup.colliderInside.SetActive(true); } } if (state[0] != localState) { localState = state[0]; stateStartTime = Time.time; if (localState == STATE_IDLE || localState == STATE_FYING) { ResetLastCupsColliders(); } if (localState == STATE_IN_CUP) { _TriggerSplash(); } } }