diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs
index ba579f193..064af6c98 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/PhysicsStaticCollision.cs
@@ -84,7 +84,7 @@ private static void Collide(ref NativeColliders colliders, ref BallState ball, r
case ColliderType.Bumper:
ref var bumperState = ref state.GetBumperState(colliderId, ref colliders);
BumperCollider.Collide(ref ball, ref state.EventQueue, ref ball.CollisionEvent, ref bumperState.RingAnimation, ref bumperState.SkirtAnimation,
- in collHeader, in bumperState.Static, ref state.Env.Random, ref state.InsideOfs);
+ in collHeader, in bumperState.Static, ref state.Env.Random, ref state.InsideOfs, bumperState.IsSwitchWiredToCoil);
break;
case ColliderType.Flipper:
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchHandler.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchHandler.cs
index b68b6d66b..34a0b7c04 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchHandler.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchHandler.cs
@@ -113,6 +113,17 @@ public void RemoveWireDest(string destId)
}
}
+ public bool HasWireDest(IWireableComponent device, string deviceItem)
+ {
+ if (_wires == null)
+ return false;
+ foreach (var wire in _wires) {
+ if (wire.Device == device && wire.DeviceItem == deviceItem)
+ return true;
+ }
+ return false;
+ }
+
///
/// Sends the switch element to the gamelogic engine and linked wires.
///
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs
index b8eeffd50..d196de961 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs
@@ -19,10 +19,7 @@
using VisualPinball.Engine.VPT.Bumper;
using System.Collections.Generic;
using Unity.Mathematics;
-using static UnityEngine.UI.Scrollbar;
-using VisualPinball.Engine.PinMAME.MPUs;
-using VisualPinball.Engine.VPT;
-using JetBrains.Annotations;
+using System.Linq;
namespace VisualPinball.Unity
{
@@ -70,43 +67,63 @@ public BumperApi(GameObject go, Player player, PhysicsEngine physicsEngine) : ba
void IApiSwitch.RemoveWireDest(string destId) => RemoveWireDest(destId);
void IApiCoil.OnCoil(bool enabled)
{
- if (!enabled) {
- return;
- }
- ref var bumperState = ref PhysicsEngine.BumperState(ItemId);
- bumperState.RingAnimation.IsHit = true;
- ref var insideOfs = ref PhysicsEngine.InsideOfs;
- List idsOfBallsInColl = insideOfs.GetIdsOfBallsInsideItem(ItemId);
- foreach (var ballId in idsOfBallsInColl) {
- if (PhysicsEngine.Balls.ContainsKey(ballId)) {
- ref var ballState = ref PhysicsEngine.BallState(ballId);
- float3 bumperPos = new(MainComponent.Position.x, MainComponent.Position.y, MainComponent.PositionZ);
- float3 ballPos = ballState.Position;
- var bumpDirection = ballPos - bumperPos;
- bumpDirection.z = 0f;
- bumpDirection = math.normalize(bumpDirection);
- var collEvent = new CollisionEventData {
- HitTime = 0f,
- HitNormal = bumpDirection,
- HitVelocity = new float2(bumpDirection.x, bumpDirection.y) * ColliderComponent.Force,
- HitDistance = 0f,
- HitFlag = false,
- HitOrgNormalVelocity = math.dot(bumpDirection, math.normalize(ballState.Velocity)),
- IsContact = true,
- ColliderId = switchColliderId,
- IsKinematic = false,
- BallId = ballId
- };
- var physicsMaterialData = ColliderComponent.PhysicsMaterialData;
- var random = PhysicsEngine.Random;
- BallCollider.Collide3DWall(ref ballState, in physicsMaterialData, in collEvent, in bumpDirection, ref random);
- ballState.Velocity += bumpDirection * ColliderComponent.Force;
- }
+ if (enabled) {
+ PhysicsEngine.ScheduleAction(0, () => {
+ ref var bumperState = ref PhysicsEngine.BumperState(ItemId);
+ bumperState.RingAnimation.IsHit = true;
+ ref var insideOfs = ref PhysicsEngine.InsideOfs;
+ List idsOfBallsInColl = insideOfs.GetIdsOfBallsInsideItem(ItemId);
+ foreach (var ballId in idsOfBallsInColl) {
+ if (PhysicsEngine.Balls.ContainsKey(ballId)) {
+ ref var ballState = ref PhysicsEngine.BallState(ballId);
+ float3 bumperPos = new(MainComponent.Position.x, MainComponent.Position.y, MainComponent.PositionZ);
+ float3 ballPos = ballState.Position;
+ var bumpDirection = ballPos - bumperPos;
+ bumpDirection.z = 0f;
+ bumpDirection = math.normalize(bumpDirection);
+ var collEvent = new CollisionEventData {
+ HitTime = 0f,
+ HitNormal = bumpDirection,
+ HitVelocity = new float2(bumpDirection.x, bumpDirection.y) * ColliderComponent.Force,
+ HitDistance = 0f,
+ HitFlag = false,
+ HitOrgNormalVelocity = math.dot(bumpDirection, math.normalize(ballState.Velocity)),
+ IsContact = true,
+ ColliderId = switchColliderId,
+ IsKinematic = false,
+ BallId = ballId
+ };
+ var physicsMaterialData = ColliderComponent.PhysicsMaterialData;
+ var random = PhysicsEngine.Random;
+ BumperCollider.PushBallAway(ref ballState, in bumperState.Static, ref collEvent, in physicsMaterialData, ref random);
+ }
+ }
+ });
}
}
void IApiWireDest.OnChange(bool enabled) => (this as IApiCoil).OnCoil(enabled);
+ internal override void AddWireDest(WireDestConfig wireConfig)
+ {
+ base.AddWireDest(wireConfig);
+ UpdateBumperWireState();
+ }
+
+ internal override void RemoveWireDest(string destId)
+ {
+ base.RemoveWireDest(destId);
+ UpdateBumperWireState();
+ }
+
+ private void UpdateBumperWireState()
+ {
+ string coilId = MainComponent.AvailableCoils.FirstOrDefault().Id;
+ BumperComponent bumperComponent = MainComponent;
+ ref var bumperState = ref PhysicsEngine.BumperState(ItemId);
+ bumperState.IsSwitchWiredToCoil = HasWireDest(bumperComponent, coilId);
+ }
+
#endregion
#region Collider Generation
@@ -156,14 +173,12 @@ void IApiHittable.OnHit(int ballId, bool isUnHit)
}
} else {
Hit?.Invoke(this, new HitEventArgs(ballId));
- if (insideOfs.GetInsideCount(ItemId) == 1) { // Must've been empty before
- ref var bumperState = ref PhysicsEngine.BumperState(ItemId);
- bumperState.SkirtAnimation.HitEvent = true;
- ref var ballState = ref PhysicsEngine.BallState(ballId);
- bumperState.SkirtAnimation.BallPosition = ballState.Position;
- Switch?.Invoke(this, new SwitchEventArgs(true, ballId));
- OnSwitch(true);
- }
+ ref var bumperState = ref PhysicsEngine.BumperState(ItemId);
+ bumperState.SkirtAnimation.HitEvent = true;
+ ref var ballState = ref PhysicsEngine.BallState(ballId);
+ bumperState.SkirtAnimation.BallPosition = ballState.Position;
+ Switch?.Invoke(this, new SwitchEventArgs(true, ballId));
+ OnSwitch(true);
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperCollider.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperCollider.cs
index 4db7d96ca..72f41486c 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperCollider.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperCollider.cs
@@ -25,13 +25,15 @@ internal static class BumperCollider
{
public static void Collide(ref BallState ball, ref NativeQueue.ParallelWriter events,
ref CollisionEventData collEvent, ref BumperRingAnimationState ringState, ref BumperSkirtAnimationState skirtState,
- in ColliderHeader collHeader, in BumperStaticState state, ref Random random, ref InsideOfs insideOfs)
+ in ColliderHeader collHeader, in BumperStaticState state, ref Random random, ref InsideOfs insideOfs, bool isSwitchWiredToCoil)
{
var wasBallInside = insideOfs.IsInsideOf(collHeader.ItemId, ball.Id);
var isBallInside = !collEvent.HitFlag;
if (isBallInside != wasBallInside) {
ball.Position += ball.Velocity * PhysicsConstants.StaticTime;
if (isBallInside) {
+ if (isSwitchWiredToCoil)
+ PushBallAway(ref ball, in state, ref collEvent, in collHeader.Material, ref random);
insideOfs.SetInsideOf(collHeader.ItemId, ball.Id);
events.Enqueue(new EventData(EventId.HitEventsHit, collHeader.ItemId, ball.Id, true));
} else {
@@ -40,5 +42,11 @@ public static void Collide(ref BallState ball, ref NativeQueue.Parall
}
}
}
+
+ public static void PushBallAway(ref BallState ballState, in BumperStaticState state, ref CollisionEventData collEvent, in PhysicsMaterialData physicsMaterialData, ref Random random)
+ {
+ BallCollider.Collide3DWall(ref ballState, in physicsMaterialData, in collEvent, in collEvent.HitNormal, ref random);
+ ballState.Velocity += collEvent.HitNormal * state.Force;
+ }
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs
index b5c66b8db..afbfdab87 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs
@@ -360,12 +360,15 @@ internal BumperState CreateState()
Speed = ringAnimComponent.RingSpeed,
} : default;
+ bool isSwitchWiredToCoil = BumperApi.HasWireDest(this, AvailableCoils.FirstOrDefault().Id);
+
return new BumperState(
skirtAnimComponent ? skirtAnimComponent.gameObject.GetInstanceID() : 0,
ringAnimComponent ? ringAnimComponent.gameObject.GetInstanceID() : 0,
staticData,
ringAnimation,
- skirtAnimation
+ skirtAnimation,
+ isSwitchWiredToCoil
);
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperState.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperState.cs
index 0013b549c..32fa6205d 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperState.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperState.cs
@@ -23,15 +23,17 @@ internal struct BumperState
internal BumperStaticState Static;
internal BumperRingAnimationState RingAnimation;
internal BumperSkirtAnimationState SkirtAnimation;
+ internal bool IsSwitchWiredToCoil;
public BumperState(int skirtItemId, int ringItemId, BumperStaticState @static,
- BumperRingAnimationState ringAnimation, BumperSkirtAnimationState skirtAnimation)
+ BumperRingAnimationState ringAnimation, BumperSkirtAnimationState skirtAnimation, bool isSwitchWiredToCoil)
{
SkirtItemId = skirtItemId;
RingItemId = ringItemId;
Static = @static;
RingAnimation = ringAnimation;
SkirtAnimation = skirtAnimation;
+ IsSwitchWiredToCoil = isSwitchWiredToCoil;
}
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemApi.cs
index 83569970f..d1427d8e0 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemApi.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemApi.cs
@@ -67,8 +67,9 @@ protected void OnInit(BallManager ballManager)
private protected IApiSwitchStatus AddSwitchDest(SwitchConfig switchConfig,IApiSwitchStatus switchStatus) => SwitchHandler.AddSwitchDest(switchConfig, switchStatus);
- internal void AddWireDest(WireDestConfig wireConfig) => SwitchHandler.AddWireDest(wireConfig);
- internal void RemoveWireDest(string destId) => SwitchHandler.RemoveWireDest(destId);
+ internal virtual void AddWireDest(WireDestConfig wireConfig) => SwitchHandler.AddWireDest(wireConfig);
+ internal virtual void RemoveWireDest(string destId) => SwitchHandler.RemoveWireDest(destId);
+ internal bool HasWireDest(IWireableComponent device, string deviceItem) => SwitchHandler.HasWireDest(device, deviceItem);
private protected void OnSwitch(bool closed) => SwitchHandler.OnSwitch(closed);