/// <summary> /// Modifies the zoom if the camera is in perspective mode /// </summary> protected virtual void PerformPerspectiveZoom() { if (!UsePerspectiveZoom || (TargetController == null)) { return; } float characterSpeed = Mathf.Abs(TargetController.Speed.x); float currentVelocity = Mathf.Max(characterSpeed, CharacterSpeed.x); float targetZoom = MMMaths.Remap(currentVelocity, CharacterSpeed.x, CharacterSpeed.y, PerspectiveZoom.x, PerspectiveZoom.y); _currentZoom = Mathf.Lerp(_currentZoom, targetZoom, Time.deltaTime * PerspectiveZoomSpeed); SetPerspectiveZoom(_currentZoom); }
/// <summary> /// Modifies the orthographic zoom /// </summary> protected virtual void PerformOrthographicZoom() { if (!UseOrthographicZoom || (TargetController == null)) { return; } float characterSpeed = Mathf.Abs(TargetController.Speed.x); float currentVelocity = Mathf.Max(characterSpeed, CharacterSpeed.x); float targetZoom = MMMaths.Remap(currentVelocity, CharacterSpeed.x, CharacterSpeed.y, OrthographicZoom.x, OrthographicZoom.y); _currentZoom = Mathf.Lerp(_currentZoom, targetZoom, Time.deltaTime * OrthographicZoomSpeed); _virtualCamera.m_Lens.OrthographicSize = _currentZoom; }
protected virtual void Decide() { _timeToNextDecision = Random.Range(DecisionTimeRange.x, DecisionTimeRange.y); _lastDecisionTimeStamp = Time.time; int dice = MMMaths.RollADice(2); if (dice == 2) { TryToMove(); } else { StopMoving(); } }
/// <summary> /// Every frame, we check if we're crouched and if we still should be /// </summary> public override void ProcessAbility() { base.ProcessAbility(); // if we don't have a model, we do nothing and exit if ((_model == null) || (_characterFly == null)) { return; } // determines and applies the rotation based on the controller speed _currentAngle = MMMaths.Remap(_controller.Speed.x, 0f, _characterFly.FlySpeed, 0f, MaximumAllowedAngle); _newRotation = Quaternion.Euler(_currentAngle * Vector3.forward); _model.transform.rotation = Quaternion.Lerp(_model.transform.rotation, _newRotation, CharacterRotationSpeed * Time.deltaTime); }
protected virtual void Sort() { Followers = FindObjectsOfType <Follower>(); // fill the bag var shuffleBag = new ShuffleBag(40); int amount = 1; float minValue = -2f; float maxValue = 2f; float newValue = 0f; for (int i = 0; i < 40; i++) { newValue = MMMaths.Remap(i, 0, 40, minValue, maxValue); if (newValue == 0f) { newValue = 2.2f; } shuffleBag.Add(newValue, amount); } float followOffset = 1f; foreach (Follower follower in Followers) { _newPosition = follower.transform.position; _newPosition.z = shuffleBag.Next() * 1.5f + Random.Range(0.01f, 0.04f); follower.transform.position = _newPosition; int dice = MMMaths.RollADice(4); float offset = shuffleBag.Next(); if (offset > 0f) { offset += 2.5f; } else { offset -= 2.5f; } follower.gameObject.GetComponentNoAlloc <MMFollowTarget>().SetXOffset(offset); follower.gameObject.GetComponentNoAlloc <MMFollowTarget>().FollowPositionSpeed = Random.Range(3f, 10f); followOffset += 0.2f; } }
/// <summary> /// Determines the weapon rotation based on the current aim direction /// </summary> protected override void DetermineWeaponRotation() { if (_currentAim != Vector3.zero) { if (_direction != Vector3.zero) { CurrentAngle = Mathf.Atan2(_currentAim.y, _currentAim.x) * Mathf.Rad2Deg; CurrentAngleAbsolute = Mathf.Atan2(_currentAimAbsolute.y, _currentAimAbsolute.x) * Mathf.Rad2Deg; if (RotationMode == RotationModes.Strict4Directions || RotationMode == RotationModes.Strict8Directions) { CurrentAngle = MMMaths.RoundToClosest(CurrentAngle, _possibleAngleValues); } if (RotationMode == RotationModes.Strict2Directions) { CurrentAngle = 0f; } // we add our additional angle CurrentAngle += _additionalAngle; // we clamp the angle to the min/max values set in the inspector if (_weapon.Owner.Orientation2D != null) { if (_weapon.Owner.Orientation2D.IsFacingRight) { CurrentAngle = Mathf.Clamp(CurrentAngle, MinimumAngle, MaximumAngle); } else { CurrentAngle = Mathf.Clamp(CurrentAngle, -MaximumAngle, -MinimumAngle); } } else { CurrentAngle = Mathf.Clamp(CurrentAngle, MinimumAngle, MaximumAngle); } _lookRotation = Quaternion.Euler(CurrentAngle * Vector3.forward); RotateWeapon(_lookRotation); } } else { CurrentAngle = 0f; RotateWeapon(_initialRotation); } MMDebug.DebugDrawArrow(this.transform.position, _currentAimAbsolute.normalized, Color.green); }
/// <summary> /// Rotates the cone, interpolating the rotation if needed /// </summary> /// <param name="direction"></param> protected virtual void AimAt(Vector3 direction) { if (Interpolate) { _newAim = MMMaths.Lerp(_newAim, direction, InterpolateRate, Time.deltaTime); } else { _newAim = direction; } _angle = MMMaths.AngleBetween(this.transform.right, _newAim); _eulerAngles.y = -_angle; _coneOfVision2D.SetDirectionAndAngles(_newAim, _eulerAngles); }
protected virtual MMRadioReceiver InstantiateBlock(Vector3 newPosition, string newName) { // instantiating the block and setting its name _receiver = Instantiate(GroundPrefabToInstantiate, newPosition, Quaternion.identity, ParentContainer); _receiver.name = newName; // setting its receiver settings float distanceToDancer = Vector3.Distance(Dancer.transform.position + DancerOffset, newPosition); float maxDistance = Mathf.Max(NumberOfColumns * Depth, NumberOfRows * Width) / 2f; float remappedDistance = MMMaths.Remap(distanceToDancer, 0f, maxDistance, 0f, 1f); float newAmplitude = Amplitude.Evaluate(remappedDistance); float random = Random.Range(MinRandom, MaxRandom); newAmplitude *= random; newAmplitude *= AmplitudeMultiplier; int channel = Random.Range(0, 2); _receiver.MinRandomLevelMultiplier = newAmplitude; _receiver.MaxRandomLevelMultiplier = newAmplitude; _receiver.GenerateRandomLevelMultiplier(); _receiver.Channel = channel; // setting its material float randomMaterial = Random.Range(0f, 100f); if (randomMaterial < 80f) { _receiver.GetComponent <MeshRenderer>().material = GroundMaterial; } else { if (randomMaterial < 90f) { _receiver.GetComponent <MeshRenderer>().material = GroundMaterialAlt1; } else { _receiver.GetComponent <MeshRenderer>().material = GroundMaterialAlt2; } } // setting its position _receiver.transform.position = newPosition; return(_receiver); }
/// <summary> /// Determines the direction of the ray we have to cast /// </summary> protected virtual void DetermineDirection() { if (RandomSpread) { _randomSpreadDirection = MMMaths.RandomVector3(-Spread, Spread); Quaternion spread = Quaternion.Euler(_randomSpreadDirection); _randomSpreadDirection = (Mode == Modes.ThreeD) ? spread * transform.forward : spread * transform.right; if (RotateWeaponOnSpread) { this.transform.rotation = this.transform.rotation * spread; } } else { _randomSpreadDirection = (Mode == Modes.ThreeD) ? transform.forward : transform.right; } }
/// <summary> /// Applies fall damage /// </summary> /// <param name="distance"></param> protected virtual void ApplyDamage(float distance) { int damageToApply = (int)Mathf.Round(MMMaths.Remap(distance, MinimumDamageFallHeight, MaximumDamageFallHeight, (float)MinimumDamage, (float)MaximumDamage)); if (ClampedDamage) { damageToApply = (int)Mathf.Clamp(damageToApply, (float)MinimumDamage, (float)MaximumDamage); } if (!_startFeedbackIsPlaying) { PlayAbilityStartFeedbacks(); } _health.Damage(damageToApply, this.gameObject, 0.2f, 0.2f); _damageThisFrame = true; }
/// <summary> /// Draws on the scene view cubes to show the minimum and maximum gaps, for tweaking purposes. /// </summary> protected virtual void OnDrawGizmosSelected() { DrawClamps(); GUIStyle style = new GUIStyle(); // we rotate the Gizmos matrix to have the gap cubes aligned to our spawner's rotation Gizmos.matrix = transform.localToWorldMatrix; // Draws a cube showing the minimum gap Gizmos.color = Color.yellow; Gizmos.DrawWireCube(Vector3.zero, MinimumGap); // Draws a cube showing the maximum gap Gizmos.color = Color.red; Gizmos.DrawWireCube(Vector3.zero, MaximumGap); // we reset our matrix rotation as to not affect other gizmo calls Gizmos.matrix = Matrix4x4.identity; // if the minimumGap cube ain't null, we draw it around our object to show the minimum gap that'll be applied to a spawned object if (MinimumGap != Vector3.zero) { style.normal.textColor = Color.yellow; Vector3 labelPosition = transform.position + (Mathf.Abs(MinimumGap.y / 2) + 1) * Vector3.up + Vector3.left; labelPosition = MMMaths.RotatePointAroundPivot(labelPosition, transform.position, transform.rotation.eulerAngles); #if UNITY_EDITOR UnityEditor.Handles.Label(labelPosition, "Minimum Gap", style); #endif } // if the maximumGap cube ain't null, we draw it around our object to show the maximum gap that'll be applied to a spawned object if (MaximumGap != Vector3.zero) { style.normal.textColor = Color.red; Vector3 labelPosition = transform.position + (-Mathf.Abs(MaximumGap.y / 2) + 1) * Vector3.up + Vector3.left; labelPosition = MMMaths.RotatePointAroundPivot(labelPosition, transform.position, transform.rotation.eulerAngles); #if UNITY_EDITOR UnityEditor.Handles.Label(labelPosition, "Maximum Gap", style); #endif } // we draw an arrow showing the direction of the spawns MMDebug.DrawGizmoArrow(transform.position, transform.rotation * Vector3.left * 10, Color.green); }
/// <summary> /// Determines the direction of the ray we have to cast /// </summary> protected virtual void DetermineDirection() { _direction = Flipped ? -transform.right : transform.right; if (RandomSpread) { _randomSpreadDirection = MMMaths.RandomVector3(-Spread, Spread); Quaternion spread = Quaternion.Euler(_randomSpreadDirection); _randomSpreadDirection = spread * _direction; if (RotateWeaponOnSpread) { this.transform.rotation = this.transform.rotation * spread; } } else { _randomSpreadDirection = _direction; } }
/// <summary> /// Determines the weapon rotation based on the current aim direction /// </summary> protected override void DetermineWeaponRotation() { if (ReticleMovesWithSlopes) { AimAt(_slopeTargetPosition); return; } if (Unrestricted3DAim) { AimAt(this.transform.position + _weaponAimCurrentAim); return; } if (_weaponAimCurrentAim != Vector3.zero) { if (_direction != Vector3.zero) { CurrentAngle = Mathf.Atan2(_weaponAimCurrentAim.z, _weaponAimCurrentAim.x) * Mathf.Rad2Deg; if (RotationMode == RotationModes.Strict4Directions || RotationMode == RotationModes.Strict8Directions) { CurrentAngle = MMMaths.RoundToClosest(CurrentAngle, _possibleAngleValues); } // we add our additional angle CurrentAngle += _additionalAngle; // we clamp the angle to the min/max values set in the inspector CurrentAngle = Mathf.Clamp(CurrentAngle, MinimumAngle, MaximumAngle); CurrentAngle = -CurrentAngle + 90f; _lookRotation = Quaternion.Euler(CurrentAngle * Vector3.up); RotateWeapon(_lookRotation); } } else { CurrentAngle = 0f; RotateWeapon(_initialRotation); } }
/// <summary> /// Computes the relative speeds /// </summary> protected virtual void ComputeRelativeSpeeds() { _newSpeed = (this.transform.position - _positionLastFrame) / Time.deltaTime; // relative speed if (_characterHandleWeapon == null) { _relativeSpeed = MovementRotatingModel.transform.InverseTransformVector(_newSpeed); } else { _relativeSpeed = WeaponRotatingModel.transform.InverseTransformVector(_newSpeed); } // remapped speed if (_characterRun != null) { _remappedSpeed.x = MMMaths.Remap(_relativeSpeed.x, 0f, _characterRun.RunSpeed, 0f, 1f); _remappedSpeed.y = MMMaths.Remap(_relativeSpeed.y, 0f, _characterRun.RunSpeed, 0f, 1f); _remappedSpeed.z = MMMaths.Remap(_relativeSpeed.z, 0f, _characterRun.RunSpeed, 0f, 1f); } // relative speed normalized _relativeSpeedNormalized = _relativeSpeed.normalized; // RotationSpeed if (Mathf.Abs(_modelAnglesYLastFrame - ModelAngles.y) > 1f) { _rotationSpeed = Mathf.Abs(_modelAnglesYLastFrame - ModelAngles.y); } else { _rotationSpeed -= Time.time * RotationSpeedResetSpeed; } if (_rotationSpeed <= 0f) { _rotationSpeed = 0f; } _modelAnglesYLastFrame = ModelAngles.y; _positionLastFrame = this.transform.position; }
protected virtual void Decide() { _timeToNextDecision = Random.Range(DecisionTimeRange.x, DecisionTimeRange.y); _lastDecisionTimeStamp = Time.time; int dice = MMMaths.RollADice(5); if (dice == 1) { PickNewTarget(); } if (dice == 2) { StopMoving(); } if ((dice == 3) || (dice == 4) || (dice == 5)) { StartMoving(); } }
/// <summary> /// Applies the offset specified in the inspector /// </summary> protected virtual void ApplyOffset() { _weaponAttachmentOffset = WeaponAttachmentOffset; if (Flipped) { _weaponAttachmentOffset.x = -WeaponAttachmentOffset.x; } if (_characterGravity != null) { _weaponAttachmentOffset = MMMaths.RotateVector2(_weaponAttachmentOffset, _characterGravity.GravityAngle); } // we apply the offset if (transform.parent != null) { _weaponOffset = transform.parent.position + _weaponAttachmentOffset; transform.position = _weaponOffset; } }
/// <summary> /// Rotates the target object, interpolating the rotation if needed /// </summary> /// <param name="direction"></param> protected virtual void AimAt(Vector3 direction) { if (Interpolate) { _newAim = MMMaths.Lerp(_newAim, direction, InterpolateRate, Time.deltaTime); } else { _newAim = direction; } switch (Axis) { case PossibleAxis.Forward: GameObjectToAim.transform.forward = _newAim; break; case PossibleAxis.Right: GameObjectToAim.transform.right = _newAim; break; } }
protected virtual void Transition(bool entering, Vector2 gravityDirection) { float gravityAngle = 180 - MMMaths.AngleBetween(Vector2.up, gravityDirection); if (TransitionForcesMode == TransitionForcesModes.Nothing) { return; } if (TransitionForcesMode == TransitionForcesModes.Reset) { return; //_controller.SetForce(Vector2.zero); //_movement.ChangeState(CharacterStates.MovementStates.Idle); } if (TransitionForcesMode == TransitionForcesModes.Adapt) { // the angle is calculated depending on if the player enters or exits a zone and takes _previousGravityAngle as parameter if you glide over from one zone to another float rotationAngle = entering ? _previousGravityAngle - gravityAngle : gravityAngle - _defaultGravityAngle; return; //_controller.SetForce(Quaternion.Euler(0, 0, rotationAngle) * _controller.Speed); } _previousGravityAngle = entering ? gravityAngle : _defaultGravityAngle; }
/// <summary> /// Follows the target, lerping the position or not based on what's been defined in the inspector /// </summary> protected virtual void FollowTargetPosition() { if (Target == null) { return; } if (!FollowPosition) { return; } var pos = Target.position; var targetPosition = new Vector3(pos.x, pos.y, this.transform.position.z); _newTargetPosition = targetPosition + Offset; float trueDistance = 0f; _direction = (_newTargetPosition - this.transform.position).normalized; trueDistance = Vector3.Distance(this.transform.position, _newTargetPosition); _speed = (_speed < FollowPositionSpeed) ? _speed + FollowAcceleration * Time.deltaTime : FollowPositionSpeed; float interpolatedDistance = trueDistance; if (InterpolatePosition) { interpolatedDistance = MMMaths.Lerp(0f, trueDistance, _speed, Time.deltaTime); this.transform.Translate(_direction * interpolatedDistance, Space.World); } else { this.transform.Translate(_direction * interpolatedDistance, Space.World); } }
protected virtual void Spawn() { if (EnemiesSpawned >= MaxEnemies) { return; } _lastSpawnAt = Time.time; _nextSpawnIn = Random.Range(SpawnFrequencyMin, SpawnFrequencyMax); GameObject nextGameObject = ObjectPooler.GetPooledGameObject(); if (nextGameObject != null) { nextGameObject.transform.position = MMMaths.RandomVector3(MinTargetRange, MaxTargetRange); nextGameObject.gameObject.SetActive(true); EnemiesSpawned++; } else { MMDebug.DebugLogTime("pooled object is null"); } }
/// <summary> /// Casts rays to the sides of the character, from its center axis. /// If we hit a wall/slope, we check its angle and move or not according to it. /// </summary> protected override void CastRaysToTheSides(float raysDirection) { // we determine the origin of our rays _horizontalRayCastFromBottom = (_boundsBottomRightCorner + _boundsBottomLeftCorner) / 2; _horizontalRayCastToTop = (_boundsTopLeftCorner + _boundsTopRightCorner) / 2; _horizontalRayCastFromBottom = _horizontalRayCastFromBottom + (Vector2)transform.up * _obstacleHeightTolerance; _horizontalRayCastToTop = _horizontalRayCastToTop - (Vector2)transform.up * _obstacleHeightTolerance; // we determine the length of our rays float horizontalRayLength = Mathf.Abs(_speed.x * Time.deltaTime) + _boundsWidth / 2 + RayOffset * 2; // we resize our storage if needed if (_sideHitsStorage.Length != NumberOfHorizontalRays) { _sideHitsStorage = new RaycastHit2D[NumberOfHorizontalRays]; } SetTemporaryLayer(); // we cast rays to the sides for (int i = 0; i < NumberOfHorizontalRays; i++) { Vector2 rayOriginPoint = Vector2.Lerp(_horizontalRayCastFromBottom, _horizontalRayCastToTop, (float)i / (float)(NumberOfHorizontalRays - 1)); // if we were grounded last frame and if this is our first ray, we don't cast against one way platforms if (State.WasGroundedLastFrame && i == 0) { _sideHitsStorage[i] = MMDebug.RayCast(rayOriginPoint, raysDirection * (transform.right), horizontalRayLength, PlatformMask, MMColors.Indigo, Parameters.DrawRaycastsGizmos); } else { _sideHitsStorage[i] = MMDebug.RayCast(rayOriginPoint, raysDirection * (transform.right), horizontalRayLength, PlatformMask & ~OneWayPlatformMask & ~MovingOneWayPlatformMask, MMColors.Indigo, Parameters.DrawRaycastsGizmos); } // if we've hit something if (_sideHitsStorage[i].distance > 0) { // if this collider is on our ignore list, we break if (_sideHitsStorage[i].collider == _ignoredCollider) { break; } // we determine and store our current lateral slope angle float hitAngle = Mathf.Abs(Vector2.Angle(_sideHitsStorage[i].normal, transform.up)); if (OneWayPlatformMask.MMContains(_sideHitsStorage[i].collider.gameObject)) { if (hitAngle > 90) { break; } } // we check if this is our movement direction if (_movementDirection == raysDirection) { State.LateralSlopeAngle = hitAngle; } // if the lateral slope angle is higher than our maximum slope angle, then we've hit a wall, and stop x movement accordingly if (hitAngle > Parameters.MaximumSlopeAngle) { if (raysDirection < 0) { State.IsCollidingLeft = true; State.DistanceToLeftCollider = _sideHitsStorage[i].distance; } else { State.IsCollidingRight = true; State.DistanceToRightCollider = _sideHitsStorage[i].distance; } if (_movementDirection == raysDirection) { CurrentWallCollider = _sideHitsStorage[i].collider.gameObject; State.SlopeAngleOK = false; float distance = MMMaths.DistanceBetweenPointAndLine(_sideHitsStorage[i].point, _horizontalRayCastFromBottom, _horizontalRayCastToTop); if (raysDirection <= 0) { _newPosition.x = -distance + _boundsWidth / 2 + RayOffset * 2; } else { _newPosition.x = distance - _boundsWidth / 2 - RayOffset * 2; } // if we're in the air, we prevent the character from being pushed back. if (!State.IsGrounded && (Speed.y != 0)) { _newPosition.x = 0; } _contactList.Add(_sideHitsStorage[i]); _speed.x = 0; } break; } } } SetOriginalLayer(); }
/// <summary> /// Every frame, we cast a number of rays below our character to check for platform collisions /// </summary> protected override void CastRaysBelow() { _friction = 0; if (_newPosition.y < -_smallValue) { State.IsFalling = true; } else { State.IsFalling = false; } if ((Parameters.Gravity > 0) && (!State.IsFalling)) { State.IsCollidingBelow = false; return; } float rayLength = (_boundsHeight / 2) + RayOffset; if (State.OnAMovingPlatform) { rayLength *= 2; } if (_newPosition.y < 0) { rayLength += Mathf.Abs(_newPosition.y); } _verticalRayCastFromLeft = (_boundsBottomLeftCorner + _boundsTopLeftCorner) / 2; _verticalRayCastToRight = (_boundsBottomRightCorner + _boundsTopRightCorner) / 2; _verticalRayCastFromLeft += (Vector2)transform.up * RayOffset; _verticalRayCastToRight += (Vector2)transform.up * RayOffset; _verticalRayCastFromLeft += (Vector2)transform.right * _newPosition.x; _verticalRayCastToRight += (Vector2)transform.right * _newPosition.x; if (_belowHitsStorage.Length != NumberOfVerticalRays) { _belowHitsStorage = new RaycastHit2D[NumberOfVerticalRays]; } _raysBelowLayerMaskPlatforms = PlatformMask; _raysBelowLayerMaskPlatformsWithoutOneWay = PlatformMask & ~MidHeightOneWayPlatformMask & ~OneWayPlatformMask & ~MovingOneWayPlatformMask; _raysBelowLayerMaskPlatformsWithoutMidHeight = _raysBelowLayerMaskPlatforms & ~MidHeightOneWayPlatformMask; // if what we're standing on is a mid height oneway platform, we turn it into a regular platform for this frame only if (StandingOnLastFrame != null) { _savedBelowLayer = StandingOnLastFrame.layer; if (MidHeightOneWayPlatformMask.MMContains(StandingOnLastFrame.layer)) { StandingOnLastFrame.layer = LayerMask.NameToLayer("Platforms"); } } // if we were grounded last frame, and not on a one way platform, we ignore any one way platform that would come in our path. if (State.WasGroundedLastFrame) { if (StandingOnLastFrame != null) { if (!MidHeightOneWayPlatformMask.MMContains(StandingOnLastFrame.layer)) { _raysBelowLayerMaskPlatforms = _raysBelowLayerMaskPlatformsWithoutMidHeight; } } } // stairs management if (State.WasGroundedLastFrame) { if (StandingOnLastFrame != null) { if (StairsMask.MMContains(StandingOnLastFrame.layer)) { // if we're still within the bounds of the stairs if (StandingOnCollider.bounds.Contains(_colliderBottomCenterPosition)) { _raysBelowLayerMaskPlatforms = _raysBelowLayerMaskPlatforms & ~OneWayPlatformMask | StairsMask; } } } } if (State.OnAMovingPlatform && (_newPosition.y > 0)) { _raysBelowLayerMaskPlatforms = _raysBelowLayerMaskPlatforms & ~OneWayPlatformMask; } float smallestDistance = float.MaxValue; int smallestDistanceIndex = 0; bool hitConnected = false; SetTemporaryLayer(); for (int i = 0; i < NumberOfVerticalRays; i++) { Vector2 rayOriginPoint = Vector2.Lerp(_verticalRayCastFromLeft, _verticalRayCastToRight, (float)i / (float)(NumberOfVerticalRays - 1)); if ((_newPosition.y > 0) && (!State.WasGroundedLastFrame)) { _belowHitsStorage[i] = MMDebug.RayCast(rayOriginPoint, -transform.up, rayLength, _raysBelowLayerMaskPlatformsWithoutOneWay, Color.blue, Parameters.DrawRaycastsGizmos); } else { _belowHitsStorage[i] = MMDebug.RayCast(rayOriginPoint, -transform.up, rayLength, _raysBelowLayerMaskPlatforms, Color.blue, Parameters.DrawRaycastsGizmos); } float distance = MMMaths.DistanceBetweenPointAndLine(_belowHitsStorage [smallestDistanceIndex].point, _verticalRayCastFromLeft, _verticalRayCastToRight); if (_belowHitsStorage[i]) { if (_belowHitsStorage[i].collider == _ignoredCollider) { continue; } hitConnected = true; State.BelowSlopeAngle = Vector2.Angle(_belowHitsStorage[i].normal, transform.up); _crossBelowSlopeAngle = Vector3.Cross(transform.up, _belowHitsStorage [i].normal); if (_crossBelowSlopeAngle.z < 0) { State.BelowSlopeAngle = -State.BelowSlopeAngle; } if (_belowHitsStorage[i].distance < smallestDistance) { smallestDistanceIndex = i; smallestDistance = _belowHitsStorage[i].distance; } } if (distance < _smallValue) { break; } } SetOriginalLayer(); if (hitConnected) { StandingOn = _belowHitsStorage[smallestDistanceIndex].collider.gameObject; StandingOnCollider = _belowHitsStorage [smallestDistanceIndex].collider; // if the character is jumping onto a (1-way) platform but not high enough, we do nothing if ( !State.WasGroundedLastFrame && (smallestDistance < _boundsHeight / 2) && ( OneWayPlatformMask.MMContains(StandingOn.layer) || MovingOneWayPlatformMask.MMContains(StandingOn.layer) ) ) { State.IsCollidingBelow = false; return; } State.IsFalling = false; State.IsCollidingBelow = true; // if we're applying an external force (jumping, jetpack...) we only apply that if (_externalForce.y > 0 && _speed.y > 0) { _newPosition.y = _speed.y * Time.deltaTime; State.IsCollidingBelow = false; } // if not, we just adjust the position based on the raycast hit else { float distance = MMMaths.DistanceBetweenPointAndLine(_belowHitsStorage [smallestDistanceIndex].point, _verticalRayCastFromLeft, _verticalRayCastToRight); _newPosition.y = -distance + _boundsHeight / 2 + RayOffset; } if (!State.WasGroundedLastFrame && _speed.y > 0) { _newPosition.y += _speed.y * Time.deltaTime; } if (Mathf.Abs(_newPosition.y) < _smallValue) { _newPosition.y = 0; } // we check if whatever we're standing on applies a friction change _frictionTest = _belowHitsStorage[smallestDistanceIndex].collider.gameObject.MMGetComponentNoAlloc <SurfaceModifier>(); if (_frictionTest != null) { _friction = _belowHitsStorage[smallestDistanceIndex].collider.GetComponent <SurfaceModifier>().Friction; } // we check if the character is standing on a moving platform _movingPlatformTest = _belowHitsStorage[smallestDistanceIndex].collider.gameObject.MMGetComponentNoAlloc <MMPathMovement>(); if (_movingPlatformTest != null && State.IsGrounded) { _movingPlatform = _movingPlatformTest.GetComponent <MMPathMovement>(); } else { DetachFromMovingPlatform(); } } else { State.IsCollidingBelow = false; if (State.OnAMovingPlatform) { DetachFromMovingPlatform(); } } if (StickToSlopes) { StickToSlope(); } }
protected virtual void Shake() { _remappedTimeSinceStart = MMMaths.Remap(Time.time - _shakeStartedTimestamp, 0f, ShakeDuration, 0f, 1f); _chromaticAberration.intensity.value = ShakeIntensity.Evaluate(_remappedTimeSinceStart); }
/// <summary> /// Instantiates cubes to form a ground and randomizes their settings /// </summary> protected virtual void GenerateGround() { int counter = 0; List <GameObject> list = new List <GameObject>(); for (int i = 0; i < ParentContainer.transform.childCount; i++) { list.Add(ParentContainer.transform.GetChild(i).gameObject); } foreach (GameObject child in list) { counter++; if (Application.isPlaying) { Destroy(child.gameObject); } else { DestroyImmediate(child.gameObject); } } _counter = 0; // we instantiate our ground grid for (int i = 0; i < NumberOfRows; i++) { for (int j = 0; j < NumberOfColumns; j++) { _wipPosition.x = i * Width; _wipPosition.y = 0; _wipPosition.z = j * Depth; _wipPosition += Offset; _wipName = "GroundBlock_" + _counter; InstantiateBlock(_wipPosition, _wipName); _counter++; } } // we generate some floating cubes too for (int i = 0; i < NumberOfRows; i++) { for (int j = 0; j < NumberOfColumns; j++) { _wipPosition.x = i * Width; _wipPosition.y = Random.Range(MinHeight, MaxHeight); _wipPosition.z = j * Depth; _wipPosition += Offset; if ((MMMaths.Chance(FloatingBlockChance)) && (Vector3.Distance(_wipPosition, Dancer.transform.position) > MinDistanceToDancer)) { _wipName = "AirBlock_" + _counter; _receiver = InstantiateBlock(_wipPosition, _wipName); _receiver.transform.localScale = _receiver.transform.localScale * Random.Range(MinScale, MaxScale); _receiver.MinRandomLevelMultiplier *= 3f; _receiver.MaxRandomLevelMultiplier *= 3f; MMAutoRotate autoRotate = _receiver.gameObject.AddComponent <MMAutoRotate>(); autoRotate.RotationSpeed = new Vector3(0f, 100f, 0f); _counter++; } } } }
void Update() { BaseUpdate(); Flyer.transform.position = MMMaths.RotatePointAroundPivot(Flyer.transform.position, Pivot.transform.position, perAngle); }
public bool Teleport(Vector2 destination, float maxRetryDistance) { return(this.Teleport(destination, (MMMaths.Vector3ToVector2(base.transform.position) - destination).normalized, maxRetryDistance)); }
/// <summary> /// Called when turning, rotates the snake's head, changes its direction, plays a feedback /// </summary> public virtual void Turn() { TurnFeedback?.PlayFeedbacks(); Direction = MMMaths.RotateVector2(Direction, 90f); this.transform.Rotate(new Vector3(0f, 0f, 90f)); }
/// <summary> /// Finds the closest gravity point and changes the gravity if needed /// </summary> protected virtual void ComputeGravityPoints() { // if we're not affected by gravity points, we do nothing and exit if (!SubjectToGravityPoints) { return; } // if we're in a gravity zone, we do nothing and exit if (_inAGravityZone) { return; } // we grab the closest gravity point _closestGravityPoint = GetClosestGravityPoint(); // if it's not null if (_closestGravityPoint != null) { // our new gravity point becomes the closest if we didn't have one already, otherwise we stay on the last gravity point met for now _newGravityPoint = (_lastGravityPoint == null) ? _closestGravityPoint : _lastGravityPoint; // if we've got a new gravity point if ((_lastGravityPoint != _closestGravityPoint) && (_lastGravityPoint != null)) { // if we haven't entered a new gravity point in a while, we switch to that new gravity point if (Time.time - _entryTimeStampPoints >= InactiveBufferDuration) { _entryTimeStampPoints = Time.time; _newGravityPoint = _closestGravityPoint; Transition(true, _newGravityPoint.transform.position - _controller.ColliderCenterPosition); StartRotating(); } } // if we didn't have a gravity point last time, we switch to this new one if (_lastGravityPoint == null) { if (Time.time - _entryTimeStampPoints >= InactiveBufferDuration) { _entryTimeStampPoints = Time.time; _newGravityPoint = _closestGravityPoint; Transition(true, _newGravityPoint.transform.position - _controller.ColliderCenterPosition); StartRotating(); } } // we override our gravity _gravityPointDirection = _newGravityPoint.transform.position - _controller.ColliderCenterPosition; float gravityAngle = 180 - MMMaths.AngleBetween(Vector2.up, _gravityPointDirection); _gravityOverridden = true; _overrideGravityAngle = gravityAngle; _lastGravityPoint = _newGravityPoint; } else { // if we don't have a gravity point in range, our gravity is not overridden if (Time.time - _entryTimeStampPoints >= InactiveBufferDuration) { if (_lastGravityPoint != null) { Transition(false, _newGravityPoint.transform.position - _controller.ColliderCenterPosition); StartRotating(); } _entryTimeStampPoints = Time.time; _gravityOverridden = false; _lastGravityPoint = null; } } }
public override GameObject SpawnProjectile(Vector3 spawnPosition, int projectileIndex, int totalProjectiles, bool triggerObjectActivation = true) { /// we get the next object in the pool and make sure it's not null GameObject nextGameObject = ObjectPooler.GetPooledGameObject(); // mandatory checks if (nextGameObject == null) { return(null); } if (nextGameObject.GetComponent <MMPoolableObject>() == null) { throw new Exception(gameObject.name + " is trying to spawn objects that don't have a PoolableObject component."); } // we position the object nextGameObject.transform.position = spawnPosition; if (_projectileSpawnTransform != null) { nextGameObject.transform.position = _projectileSpawnTransform.position; } // we set its direction Projectile projectile = nextGameObject.GetComponent <Projectile>(); if (projectile != null) { projectile.SetDamage((int)(DamageCaused * _damageMultiplier)); projectile.SetWeapon(this); if (Owner != null) { projectile.SetOwner(Owner.gameObject); } } // we activate the object nextGameObject.gameObject.SetActive(true); if (projectile != null) { if (RandomSpread) { _randomSpreadDirection.x = UnityEngine.Random.Range(-Spread.x, Spread.x); _randomSpreadDirection.y = UnityEngine.Random.Range(-Spread.y, Spread.y); _randomSpreadDirection.z = UnityEngine.Random.Range(-Spread.z, Spread.z); } else { if (totalProjectiles > 1) { _randomSpreadDirection.x = MMMaths.Remap(projectileIndex, 0, totalProjectiles - 1, -Spread.x, Spread.x); _randomSpreadDirection.y = MMMaths.Remap(projectileIndex, 0, totalProjectiles - 1, -Spread.y, Spread.y); _randomSpreadDirection.z = MMMaths.Remap(projectileIndex, 0, totalProjectiles - 1, -Spread.z, Spread.z); } else { _randomSpreadDirection = Vector3.zero; } } Quaternion spread = Quaternion.Euler(_randomSpreadDirection); if (Owner == null) { projectile.SetDirection(spread * transform.forward, transform.rotation, true); } else { if (Owner.CharacterDimension == Character.CharacterDimensions.Type3D) { projectile.SetDirection(spread * transform.forward, transform.rotation, true); } else { Vector3 newDirection = (spread * transform.right) * (Flipped ? -1 : 1); if (Owner.Orientation2D != null) { projectile.SetDirection(newDirection, transform.rotation, Owner.Orientation2D.IsFacingRight); } else { projectile.SetDirection(newDirection, transform.rotation, true); } } } if (RotateWeaponOnSpread) { this.transform.rotation = this.transform.rotation * spread; } } if (triggerObjectActivation) { if (nextGameObject.GetComponent <MMPoolableObject>() != null) { nextGameObject.GetComponent <MMPoolableObject>().TriggerOnSpawnComplete(); } } return(nextGameObject); }
/// <summary> /// Computes the current aim direction /// </summary> protected virtual void GetCurrentAim() { if (_weapon.Owner == null) { return; } if ((_weapon.Owner.LinkedInputManager == null) && (_weapon.Owner.CharacterType == Character.CharacterTypes.Player)) { return; } switch (AimControl) { case AimControls.Off: if (_weapon.Owner == null) { return; } _currentAim = Vector2.right; _direction = Vector2.right; if (_characterGravity != null) { _currentAim = _characterGravity.transform.right; _direction = _characterGravity.transform.right; } break; case AimControls.Script: _currentAim = (_weapon.Owner.IsFacingRight) ? _currentAim : -_currentAim; _direction = -(transform.position - _currentAim); break; case AimControls.PrimaryMovement: if (_weapon.Owner == null) { return; } if (_weapon.Owner.IsFacingRight) { _currentAim = _weapon.Owner.LinkedInputManager.PrimaryMovement; _direction = transform.position + _currentAim; } else { _currentAim = -_weapon.Owner.LinkedInputManager.PrimaryMovement; _direction = -(transform.position - _currentAim); } if (_characterGravity != null) { _currentAim = MMMaths.RotateVector2(_currentAim, _characterGravity.GravityAngle); if (_characterGravity.ShouldReverseInput()) { _currentAim = -_currentAim; } } break; case AimControls.SecondaryMovement: if (_weapon.Owner == null) { return; } if (_weapon.Owner.IsFacingRight) { _currentAim = _weapon.Owner.LinkedInputManager.SecondaryMovement; _direction = transform.position + _currentAim; } else { _currentAim = -_weapon.Owner.LinkedInputManager.SecondaryMovement; _direction = -(transform.position - _currentAim); } break; case AimControls.Mouse: if (_weapon.Owner == null) { return; } _mousePosition = Input.mousePosition; _mousePosition.z = 10; _direction = Camera.main.ScreenToWorldPoint(_mousePosition); _direction.z = transform.position.z; if (_weapon.Owner.IsFacingRight) { _currentAim = _direction - transform.position; } else { _currentAim = transform.position - _direction; } break; } }