Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move bumper impulse into physics loop #491

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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 @@ -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:
Expand Down
11 changes: 11 additions & 0 deletions VisualPinball.Unity/VisualPinball.Unity/Game/SwitchHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/// <summary>
/// Sends the switch element to the gamelogic engine and linked wires.
/// </summary>
Expand Down
103 changes: 59 additions & 44 deletions VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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<int> 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<int> 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
Expand Down Expand Up @@ -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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ internal static class BumperCollider
{
public static void Collide(ref BallState ball, ref NativeQueue<EventData>.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 {
Expand All @@ -40,5 +42,11 @@ public static void Collide(ref BallState ball, ref NativeQueue<EventData>.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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
5 changes: 3 additions & 2 deletions VisualPinball.Unity/VisualPinball.Unity/VPT/ItemApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down