I wrote a script for GTA V that adds vehicles in range to a list, and then checks for collisions between them. Whenever there is a collision damage is applied to passengers, based on speed difference before/after the collision. The problem is when more than one car is supposed to take damage, the script enters the loop to apply the damage, and other vehicle's collisions aren't registered. How should I implement this? I want multiple cars collisions to be calculated simultaneously.
Here is my current implementation:
public void pedDamage()
{
Ped player = Game.Player.Character;
List<Vehicle> pedVehs = new List<Vehicle>(World.GetNearbyVehicles(player, range));
foreach (Vehicle pedv in pedVehs)
{
if (pedv.HasCollided)
{
pedSpeed = pedv.Speed;
Wait(0);
pedAfterSpeed = pedv.Speed;
pedSpeedDif = pedSpeed - pedAfterSpeed;
dmgPed = pedSpeedDif * pedMultiplier * 5;
if (dmgPed <= 0)
{
dmgPed = dmgPed * -1;
}
if (dmgPed > 0)
{
if (pedv.Exists())
{
Ped dr = pedv.Driver;
if (dr != null)
{
dr.ApplyDamage((int)dmgPed);
GTA.UI.Screen.ShowHelpText("Damage: " dmgPed "Mult: " pedMultiplier, 3000, true, false);
}
if (pedv.PassengerCount > 0)
{
List<Ped> pedPsngrs = new List<Ped>(pedv.Passengers);
foreach (Ped pp in pedPsngrs)
{
if (pp != null)
{
pp.ApplyDamage((int)dmgPed);
}
}
}
}
}
else { dmgPed = 0; }
}
dmgPed = 0;
}
}
CodePudding user response:
I think (not 100% sure) the problem is the call to Wait()
. This function doesn't care which vehicle you're looking at; after the first Wait()
, any speed difference is resolved for ALL remaining vehicles.
To fix this, you need to capture the initial speed for all appropriate vehicles before waiting.
public void pedDamage()
{
var pedVehs = World.GetNearbyVehicles(player, range).
Where(v => v.HasCollided).
Select(v => new {Vehicle = v, InitialSpeed = v.Speed}).
ToList(); //use ToList to resolve lazy execution before calling Wait()
Wait(0);
foreach(var pedv in pedVehs.Where(v => v.Vehicle.Exists())
{
var pedSpeedDif = pedv.InitialSpeed - pedv.Vehicle.Speed;
var dmgPed = (int)Math.Abs(pedSpeedDif * pedMultiplier * 5);
if (dmgPed <= 0) continue;
Ped dr = pedv.Vehicle.Driver;
if (dr is object)
{
dr.ApplyDamage(dmgPed);
GTA.UI.Screen.ShowHelpText($"Damage: {dmgPed} Mult: {pedMultiplier}", 3000, true, false);
}
foreach (Ped pp in pedv.Vehicle.Passengers.Where(p => p is object))
{
pp.ApplyDamage(dmgPed);
}
}
}
Notice how much I was able to shorten the code and removed no fewer than 5 levels of indentation. Even if you're not familiar with linq, lambda expressions, or anonymous types, it should still be easier to understand how this code works over the original... especially as it how no formatting in the question. I'm sure this is also much more efficient, for all it needs to allocate an anonymous object for each colliding vehicle.
I'm not sure how your ShowHelpText()
method works, but you may also want to collect all of those messages into a single string to show once at the end, as well.