Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,34 @@ public class FlipperColliderInspector : ColliderInspector<FlipperData, FlipperCo
private SerializedProperty _flipperCorrectionProperty;

private bool _foldoutFlipperTricks = true;
private bool _foldoutLiveCatch = true;

#region Flipper Tricks

#region FlipperTricks
private SerializedProperty _useFlipperTricksPhysicsProperty;
private SerializedProperty _SOSRampUpProperty;
private SerializedProperty _SOSEMProperty;
private SerializedProperty _EOSReturnProperty;
private SerializedProperty _EOSTNewProperty;
private SerializedProperty _EOSANewProperty;
private SerializedProperty _EOSRampupProperty;
private SerializedProperty _OvershootProperty;
private SerializedProperty _BumpOnReleaseProperty;
private SerializedProperty _sosRampUpProperty;
private SerializedProperty _sosEmProperty;
private SerializedProperty _eosReturnProperty;
private SerializedProperty _eosTNewProperty;
private SerializedProperty _eosANewProperty;
private SerializedProperty _eosRampUpProperty;
private SerializedProperty _overshootProperty;
private SerializedProperty _bumpOnReleaseProperty;

#endregion

#region Live Catch

private SerializedProperty _useFlipperLiveCatch;
private SerializedProperty _liveCatchDistanceMin;
private SerializedProperty _liveCatchDistanceMax;
private SerializedProperty _liveCatchMinimalBallSpeed;
private SerializedProperty _liveCatchPerfectTime;
private SerializedProperty _liveCatchFullTime;
private SerializedProperty _liveCatchInaccurateBounceSpeedMultiplier;
private SerializedProperty _liveCatchMinimumBounceSpeedMultiplier;

#endregion

protected override void OnEnable()
{
Expand All @@ -69,18 +84,28 @@ protected override void OnEnable()
_scatterProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.Scatter));
_flipperCorrectionProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.FlipperCorrection));

#region Flipper_Tricks
#region Flipper Tricks
_useFlipperTricksPhysicsProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.useFlipperTricksPhysics));
_SOSRampUpProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.SOSRampUp));
_SOSEMProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.SOSEM));
_EOSReturnProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.EOSReturn));
_EOSTNewProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.EOSTNew));
_EOSANewProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.EOSANew));
_EOSRampupProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.EOSRampup));
_OvershootProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.Overshoot));
_BumpOnReleaseProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.BumpOnRelease));
_sosRampUpProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.SOSRampUp));
_sosEmProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.SOSEM));
_eosReturnProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.EOSReturn));
_eosTNewProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.EOSTNew));
_eosANewProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.EOSANew));
_eosRampUpProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.EOSRampup));
_overshootProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.Overshoot));
_bumpOnReleaseProperty = serializedObject.FindProperty(nameof(FlipperColliderComponent.BumpOnRelease));
#endregion

#region Live Catch
_useFlipperLiveCatch = serializedObject.FindProperty(nameof(FlipperColliderComponent.useFlipperLiveCatch));
_liveCatchDistanceMin = serializedObject.FindProperty(nameof(FlipperColliderComponent.LiveCatchDistanceMin));
_liveCatchDistanceMax = serializedObject.FindProperty(nameof(FlipperColliderComponent.LiveCatchDistanceMax));
_liveCatchMinimalBallSpeed = serializedObject.FindProperty(nameof(FlipperColliderComponent.LiveCatchMinimalBallSpeed));
_liveCatchPerfectTime = serializedObject.FindProperty(nameof(FlipperColliderComponent.LiveCatchPerfectTime));
_liveCatchFullTime = serializedObject.FindProperty(nameof(FlipperColliderComponent.LiveCatchFullTime));
_liveCatchInaccurateBounceSpeedMultiplier = serializedObject.FindProperty(nameof(FlipperColliderComponent.LiveCatchInaccurateBounceSpeedMultiplier));
_liveCatchMinimumBounceSpeedMultiplier = serializedObject.FindProperty(nameof(FlipperColliderComponent.LiveCatchMinmalBounceSpeedMultiplier));
#endregion
}

public override void OnInspectorGUI()
Expand Down Expand Up @@ -110,20 +135,36 @@ public override void OnInspectorGUI()
}
EditorGUILayout.EndFoldoutHeaderGroup();

if (_foldoutFlipperTricks = EditorGUILayout.BeginFoldoutHeaderGroup(_foldoutFlipperTricks, "Flipper Tricks"))
{
if (_foldoutFlipperTricks = EditorGUILayout.BeginFoldoutHeaderGroup(_foldoutFlipperTricks, "Flipper Tricks")) {

PropertyField(_useFlipperTricksPhysicsProperty, "Use Flipper Tricks");

EditorGUI.BeginDisabledGroup(!_useFlipperTricksPhysicsProperty.boolValue);
PropertyField(_SOSRampUpProperty, "SOSRampUP");
PropertyField(_SOSEMProperty, "SOSEM");
PropertyField(_EOSReturnProperty, "EOSReturn");
PropertyField(_EOSTNewProperty, "EOSTNew");
PropertyField(_EOSANewProperty, "EOSANew");
PropertyField(_EOSRampupProperty, "EOSRampup");
PropertyField(_OvershootProperty, "Overshoot Angle");
PropertyField(_BumpOnReleaseProperty, "Bump on release");
PropertyField(_sosRampUpProperty, "SOSRampUP");
PropertyField(_sosEmProperty, "SOSEM");
PropertyField(_eosReturnProperty, "EOSReturn");
PropertyField(_eosTNewProperty, "EOSTNew");
PropertyField(_eosANewProperty, "EOSANew");
PropertyField(_eosRampUpProperty, "EOSRampup");
PropertyField(_overshootProperty, "Overshoot Angle");
PropertyField(_bumpOnReleaseProperty, "Bump on Release");
EditorGUI.EndDisabledGroup();

}
EditorGUILayout.EndFoldoutHeaderGroup();

if (_foldoutLiveCatch = EditorGUILayout.BeginFoldoutHeaderGroup(_foldoutLiveCatch, "Live Catch")) {

PropertyField(_useFlipperLiveCatch, "Use Live Catch");

EditorGUI.BeginDisabledGroup(!_useFlipperLiveCatch.boolValue);
PropertyField(_liveCatchDistanceMin, "Min Distance");
PropertyField(_liveCatchDistanceMax, "Max Distance");
PropertyField(_liveCatchMinimalBallSpeed, "Min Ball Speed");
PropertyField(_liveCatchPerfectTime, "Perfect Time");
PropertyField(_liveCatchFullTime, "Full Time");
PropertyField(_liveCatchMinimumBounceSpeedMultiplier, "Perfect Bounce");
PropertyField(_liveCatchInaccurateBounceSpeedMultiplier, "Inaccurate Bounce");
EditorGUI.EndDisabledGroup();
}
EditorGUILayout.EndFoldoutHeaderGroup();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ protected override void OnUpdate()
var flipperMaterialData = GetComponent<FlipperStaticData>(coll.Entity);
var flipperHitData = GetComponent<FlipperHitData>(coll.Entity);
var flipperTricksData = GetComponent<FlipperTricksData>(coll.Entity);

// do liveCatch - check before collision
FlipperCollider.LiveCatch(
ref ballData, ref collEvent, ref flipperTricksData, in flipperMaterialData, timeMsec
);
((FlipperCollider*)collider)->Collide(
ref ballData, ref collEvent, ref flipperMovementData, ref events,
in ballEntity, in flipperTricksData,in flipperMaterialData, in flipperVelocityData, in flipperHitData, timeMsec
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

using NLog;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Entities;
Expand All @@ -35,6 +36,10 @@ internal struct FlipperCollider : ICollider

public ColliderBounds Bounds { get; private set; }

public static readonly Logger Logger = LogManager.GetCurrentClassLogger();

#region Setup

public FlipperCollider(CircleCollider hitCircleBase, float flipperRadius, float startRadius, float endRadius, float startAngle, float endAngle, ColliderInfo info) : this()
{
var bounds = hitCircleBase.Bounds;
Expand Down Expand Up @@ -143,6 +148,8 @@ public unsafe void Allocate(BlobBuilder builder, ref BlobBuilderArray<BlobPtr<Co
);
}

#endregion

#region Narrowphase

public float HitTest(ref CollisionEventData collEvent, ref DynamicBuffer<BallInsideOfBufferElement> insideOfs,
Expand Down Expand Up @@ -574,7 +581,7 @@ private float HitTestFlipperEnd(ref CollisionEventData collEvent, ref FlipperHit

// hit limits ???
if (contactAng >= angleMax && angleSpeed > 0 || contactAng <= angleMin && angleSpeed < 0) {
angleSpeed = 0; // rotation stopped
angleSpeed = 0f; // rotation stopped
}

// Unit Tangent vector velocity of contact point(rotate normal right)
Expand Down Expand Up @@ -717,6 +724,56 @@ private void GetRelativeVelocity(in float3 normal, in BallData ball, in FlipperM

#endregion

#region LiveCatch

public static void LiveCatch(ref BallData ball, ref CollisionEventData collEvent, ref FlipperTricksData tricks, in FlipperStaticData matData, uint msec ) {
if (!tricks.UseFlipperLiveCatch)
return;
var normalSpeed = math.dot(collEvent.HitNormal, ball.Velocity) * -1f;
Comment thread
Cupiii marked this conversation as resolved.
// Vector from position of the flipper ball to ball
var flipperToBall = ball.Position - matData.Position;
var hitTangent = Math.CrossZ(1f, collEvent.HitNormal);
var ballPosition = math.dot(hitTangent, flipperToBall);
//Logger.Info("BallPosition = {0}", ballPosition);
if (math.abs(ballPosition) > tricks.LiveCatchDistanceMax) {
//Logger.Info("BallPosition = {0} -> no calculation", ballPosition);
return;
}
if (math.abs(ballPosition) < tricks.LiveCatchDistanceMin) {
//Logger.Info("BallPosition = {0} -> no calculation", ballPosition);
return;
}
// only test for LiveCatch if Ballspeed is greater as set Minimal Speed (default = 6)
// different to nFozzys implementation we calculate all speeds based on the angle of the flipper, not y direction.
if (normalSpeed >= tricks.LiveCatchMinimalBallSpeed) {
float catchTime = (float)(msec - tricks.FlipperAngleEndTime * 1000);
if (catchTime <= tricks.LiveCatchFullTime){
// we have a live catch, so stop the ball for now.
ball.Velocity += normalSpeed * collEvent.HitNormal;
// do we have some bounce
// as a difference to the nFozzy implementation, we don't deal with hard-coded speeds, but multiplier to current speed against the flipper.
var liveCatchBounceMultiplier = tricks.LiveCatchMinimalBounceSpeedMultiplier;
//Logger.Info("We have a live catch");
if (catchTime > tricks.LiveCatchPerfectTime) {
// but it's imperfect, so we have add some bounce
// example: hit after 10 msecs, fulltime is 16, perfect time is 8, should be (10-8)/(16-8)*inaccuracySpeedMultiplier
liveCatchBounceMultiplier = (catchTime - tricks.LiveCatchPerfectTime) / (tricks.LiveCatchFullTime - tricks.LiveCatchPerfectTime) * (tricks.LiveCatchInaccurateBounceSpeedMultiplier-tricks.LiveCatchMinimalBounceSpeedMultiplier) + tricks.LiveCatchMinimalBounceSpeedMultiplier;

}
//Logger.Info("Bounce Multiplicator is {0}, catchtime {1}", liveCatchBounceMultiplier, catchTime);
ball.Velocity -= collEvent.HitNormal * normalSpeed * liveCatchBounceMultiplier;
ball.AngularMomentum.x = 0;
ball.AngularMomentum.y = 0;

}
//Logger.Info("LiveCatchTest - Ball with y-speed {0}, at CollisionTime: {1}, livecatchTime is {2}, difference is {3} msecs", ball.Velocity.y, msec, tricks.FlipperAngleEndTime * 1000, tricks.FlipperAngleEndTime * 1000 - msec);
//Logger.Info("LiveCatchTest - normalspeed = {0}, catchTime = {1}", normalSpeed, catchTime);

}
}

#endregion

#region Collision

public void Collide(ref BallData ball, ref CollisionEventData collEvent, ref FlipperMovementData movementData,
Expand Down Expand Up @@ -786,7 +843,7 @@ public void Collide(ref BallData ball, ref CollisionEventData collEvent, ref Fli
* 0 = no falloff, 1 = half the COR at 1 m/s (18.53 speed units)
*/
var epsilon = Math.ElasticityWithFalloff(_header.Material.Elasticity, _header.Material.ElasticityFalloff, bnv);
if (tricks.useFlipperTricksPhysics)
if (tricks.UseFlipperTricksPhysics)
epsilon *= tricks.ElasticityMultiplier;

var pv1 = angResp / matData.Inertia;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

// ReSharper disable InconsistentNaming

using System;
using Unity.Entities;
using UnityEngine;
using VisualPinball.Engine.VPT.Flipper;
Expand Down Expand Up @@ -79,7 +78,7 @@ public class FlipperColliderComponent : ColliderComponent<FlipperData, FlipperCo

public override PhysicsMaterialData PhysicsMaterialData => GetPhysicsMaterialData(Elasticity, ElasticityFalloff, Friction, Scatter);

#region Flipper_Tricks
#region FlipperTricks
/// <summary>
/// If set, apply Flipper Tricks Physics (nFozzy/RothBauerW)
/// </summary>
Expand Down Expand Up @@ -120,6 +119,44 @@ public class FlipperColliderComponent : ColliderComponent<FlipperData, FlipperCo
public float BumpOnRelease = 0.4f;
#endregion

#region LiveCatch
/// <summary>
/// If set, apply Live Catch (nFozzy/RothBauerW)
/// </summary>
#endregion
[Tooltip("The nFozzy's LiveCatch Physics")]
public bool useFlipperLiveCatch = false;

[Min(0f)]
[Tooltip("Minimum distance in vp units from flipper base live catch dampening will occur")]
public float LiveCatchDistanceMin = 40f;

[Min(0f)]
[Tooltip("Maxium distance in vp units from flipper base live catch dampening will occur")]
public float LiveCatchDistanceMax = 100f;

[Min(0f)]
[Tooltip("Minimal ball speed for live catch")]
public float LiveCatchMinimalBallSpeed = 6f;

[Unit("ms")]
[Min(0f)]
[Tooltip("Maximum Time in for (perfect or imperfect) live catch")]
public float LiveCatchFullTime = 16;

[Unit("ms")]
[Min(0f)]
[Tooltip("Maximum Time for a perfect live catch")]
public float LiveCatchPerfectTime = 8;

[Min(0f)]
[Tooltip("Minimum bounce speed multiplier for a live catch (0 allows perfect live catches)")]
public float LiveCatchMinmalBounceSpeedMultiplier = 0.1f;

[Min(0f)]
[Tooltip("Maximum bounce speed multiplier for an inaccurate live catch")]
public float LiveCatchInaccurateBounceSpeedMultiplier = 1.0f;

protected override IApiColliderGenerator InstantiateColliderApi(Player player, Entity entity)
=> new FlipperApi(gameObject, entity, player);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ private FlipperTricksData GetFlipperTricksData(FlipperColliderComponent collider
{
return new FlipperTricksData
{
useFlipperTricksPhysics = colliderComponent.useFlipperTricksPhysics,
UseFlipperTricksPhysics = colliderComponent.useFlipperTricksPhysics,
SOSRampUp = colliderComponent.SOSRampUp,
SOSEM = colliderComponent.SOSEM,
EOSReturn = colliderComponent.EOSReturn,
Expand All @@ -592,7 +592,16 @@ private FlipperTricksData GetFlipperTricksData(FlipperColliderComponent collider
AngleEnd = staticData.AngleEnd,
TorqueDamping = staticData.TorqueDamping,
TorqueDampingAngle = staticData.TorqueDampingAngle,
RampUpSpeed = staticData.RampUpSpeed,
RampUpSpeed = staticData.RampUpSpeed,

UseFlipperLiveCatch = colliderComponent.useFlipperLiveCatch,
LiveCatchDistanceMin = colliderComponent.LiveCatchDistanceMin, // vp units from base
LiveCatchDistanceMax = colliderComponent.LiveCatchDistanceMax, // vp units from base
LiveCatchMinimalBallSpeed = colliderComponent.LiveCatchMinimalBallSpeed,
LiveCatchPerfectTime = colliderComponent.LiveCatchPerfectTime,
LiveCatchFullTime = colliderComponent.LiveCatchFullTime,
LiveCatchInaccurateBounceSpeedMultiplier = colliderComponent.LiveCatchInaccurateBounceSpeedMultiplier,
LiveCatchMinimalBounceSpeedMultiplier = colliderComponent.LiveCatchMinmalBounceSpeedMultiplier,

//initialize
OriginalAngleEnd = staticData.AngleEnd,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ protected override void OnUpdate()
var dTime = _simulateCycleSystemGroup.HitTime;
var events = _eventQueue.AsParallelWriter();
var marker = PerfMarker;
var currentTime = Time.ElapsedTime;

Entities.WithName("FlipperDisplacementJob").ForEach((Entity entity, ref FlipperMovementData state, in FlipperTricksData tricks,in FlipperStaticData data) => {
Entities.WithName("FlipperDisplacementJob").ForEach((Entity entity, ref FlipperMovementData state, ref FlipperTricksData tricks, in FlipperStaticData data) => {

marker.Begin();

Expand All @@ -76,6 +77,10 @@ protected override void OnUpdate()

var handleEvent = false;

if (state.Angle == tricks.AngleEnd) {
tricks.FlipperAngleEndTime = currentTime;
}

if (state.Angle >= angleMax) {
// hit stop?
if (state.AngleSpeed > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,29 @@ internal struct FlipperTricksData : IComponentData

public bool WasInContact;

// time used for live Catch
public double FlipperAngleEndTime;

// externals
public bool useFlipperTricksPhysics;
// Flipper Tricks
public bool UseFlipperTricksPhysics;
public float SOSRampUp;
public float SOSEM;
public float EOSReturn;
public float EOSTNew;
public float EOSANew;
public float EOSRampup;
public float Overshoot;

// Live Catch
public bool UseFlipperLiveCatch;
public float LiveCatchDistanceMin; // vp units from base
public float LiveCatchDistanceMax; // vp units from base
public float LiveCatchMinimalBallSpeed;
public float LiveCatchPerfectTime;
public float LiveCatchFullTime;
public float LiveCatchMinimalBounceSpeedMultiplier;
public float LiveCatchInaccurateBounceSpeedMultiplier;

}
}
Loading