Jump to content

How do you detect that you are landed a Huey on a ship ...


Frag

Recommended Posts

Hi guys,

 

I have no issue detecting that I landed a Huey on the ground. I check 3 things:

 

1. The chopper is within the landing zone (with a trigger zone)

2. The chopper speed is smaller than 1.

3. The chopper altitude is smaller than 6 feet (not sure of the value I set but you get the idea).

 

But now ... on a moving ship I cannot use this method because:

 

1. Since a boat is mostly rectangle in a round zone ... the zone each side of the ship will be considered "within the trigger zone".

2. Since the boat is moving .... I could go slower than the boat while trying to land.

3. I could also be lower than the boat deck if I fly beside it.

 

Briefly, how do you guys trigger that you landed on a boat? Any tricks that you guys use?


Edited by Frag
Link to comment
Share on other sites

I'd use an altitude check + a tiny moving trigger zone (small enough to be contained within the carrier's deck).

 

If that's not enough, you could also try adding an extra coordinate point distance check (which would make the carrier zone kind of redundant).

 

Here's a basic MOOSE example:

 

 

local CarrierUnit = UNIT:FindByName("Unit name of the carrier in ME")

local Chopper = UNIT:FindByName("Unit name of the chopper in ME")

 

local CarrierZone = ZONE_UNIT:New("Carrier_Zone", CarrierUnit, Radius, Offset) -- MOOSE constructor of moving zones based on units. Radius and Offset are optional

 

local ChopperCoordinate = Chopper:GetCoordinate()

local CarrierZoneCoordinate = CarrierZone:GetCoordinate() --This coordinate will be taken from the center of the carrier zone, if I'm not mistaken

 

local CoordinateDistanceCheck = CarrierZoneCoordinate:Get2DDistance(ChopperCoordinate) --This function will return the 2D distance between the two coordinates.

-- :Get3DDistance() is also available for COORDINATE class, but we don't need it here, since we'll use an altitude check to take care of the 3rd axis/dimension

 

local ChopperAltitudeCheck = Chopper:GetAltitude()

 

local ChopperZoneCheck = Chopper:IsInZone(CarrierZone)

 

if ChopperZoneCheck == true and ChopperAltitudeCheck <= 50 and CoordinateDistanceCheck <= 50 -- You can constrain these values even more, if you need to, keep constraining until you find the sweet spot

then

Chopper has landed!

end

 

 

You can use this method with UNIT/GROUP sets as well, just need to define the set and include the check in a suitable iterator function, like this:

 

 

local UniSet = SET_UNIT:New()

:FilterPrefixes("Common ME unit name prefix")

:FilterStart()

 

local CarrierUnit = UNIT:FindByName("Name of the carrier in ME")

local CarrierZone = ZONE_UNIT:New("Carrier_Zone", CarrierUnit, Radius, Offset)

 

UniSet:ForEachUnitCompletelyInZone(CarrierZone,

function(UnitSet)

 

local CarrierZoneCoordinate = CarrierZone:GetCoordinate()

 

local UnitSetChopperCoordinate = UnitSet:GetCoordinate()

 

local CoordinateDistanceCheck = CarrierZoneCoordinate:Get2DDistance(UnitSetChopperCoordinate)

 

local UnitSetChopperAltitude = UnitSet:GetAltitude()

 

if UnitSetChopperAltitude <= 50 and CoordinateDistanceCheck <= 50

then

 

local UnitSetChopperName = UnitSet:GetName()

 

MESSAGE:New(UnitSetChopperName.." has landed on the carrier!",10):ToAll() --This will tell you exactly which unit has landed on the carrier

end

end

)

 

 

Hope this helps!:thumbup:

 

 

EDIT: Actually, you can simply use LAND events to do this (and capture all the relevant EventData that you need), zones and altitude checks aren't even required.

I didn't mention this earlier because I mistakenly assumed that carrier landings didn't generate LAND events (they totally do, fortunately).

I've tested it and works perfectly with choppers and carriers from both coalitions (test mission attached):

 

local ChopperSet = SET_UNIT:New()

:FilterPrefixes("Choppah_") --All choppers in the test mission use this prefix in their ME unit name

:FilterStart()

 

ChopperSet:HandleEvent(EVENTS.Land)

 

function ChopperSet:OnEventLand(EventData)

 

local InitiatorChopperName = EventData.IniUnitName

local InitiatorChopper = UNIT:FindByName(InitiatorChopperName) --This will return the MOOSE unit object of the chopper that initiated the LAND event. I've included it in case you want to do stuff with it after landing

 

local LandingLocationName = EventData.PlaceName --This will return the ME unit name of the carrier involved in the landing event (in this particular case)

 

if LandingLocationName == "Stennis" or LandingLocationName == "Kuznetsov" -- No zones required, the ME unit names of the carriers are enough

then

 

MESSAGE:New(InitiatorChopperName.." has landed on "..LandingLocationName,10):ToAll() --This message will show both the unit name of the initiator chopper and the unit name of the carrier it landed on

 

Stuff you want done when the landing event happens

 

end

end

Carrier Landing Test.miz


Edited by Hardcard
Link to comment
Share on other sites

I'd use an altitude check + a tiny moving trigger zone (small enough to be contained within the carrier's deck).

 

If that's not enough, you could also try adding an extra coordinate point distance check (which would make the carrier zone kind of redundant).

 

Here's a basic MOOSE example:

 

 

local CarrierUnit = UNIT:FindByName("Unit name of the carrier in ME")

local Chopper = UNIT:FindByName("Unit name of the chopper in ME")

 

local CarrierZone = ZONE_UNIT:New("Carrier_Zone", CarrierUnit, Radius, Offset) -- MOOSE constructor of moving zones based on units. Radius and Offset are optional

 

local ChopperCoordinate = Chopper:GetCoordinate()

local CarrierZoneCoordinate = CarrierZone:GetCoordinate() --This coordinate will be taken from the center of the carrier zone, if I'm not mistaken

 

local CoordinateDistanceCheck = CarrierZoneCoordinate:Get2DDistance(ChopperCoordinate) --This function will return the 2D distance between the two coordinates.

-- :Get3DDistance() is also available for COORDINATE class, but we don't need it here, since we'll use an altitude check to take care of the 3rd axis/dimension

 

local ChopperAltitudeCheck = Chopper:GetAltitude()

 

local ChopperZoneCheck = Chopper:IsInZone(CarrierZone)

 

if ChopperZoneCheck == true and ChopperAltitudeCheck <= 50 and CoordinateDistanceCheck <= 50 -- You can constrain these values even more, if you need to, keep constraining until you find the sweet spot

then

Chopper has landed!

end

 

 

You can use this method with UNIT/GROUP sets as well, just need to define the set and include the check in a suitable iterator function, like this:

 

 

local UniSet = SET_UNIT:New()

:FilterPrefixes("Common ME unit name prefix")

:FilterStart()

 

local CarrierUnit = UNIT:FindByName("Name of the carrier in ME")

local CarrierZone = ZONE_UNIT:New("Carrier_Zone", CarrierUnit, Radius, Offset)

 

UniSet:ForEachUnitCompletelyInZone(CarrierZone,

function(UnitSet)

 

local CarrierZoneCoordinate = CarrierZone:GetCoordinate()

 

local UnitSetChopperCoordinate = UnitSet:GetCoordinate()

 

local CoordinateDistanceCheck = CarrierZoneCoordinate:Get2DDistance(UnitSetChopperCoordinate)

 

local UnitSetChopperAltitude = UnitSet:GetAltitude()

 

if UnitSetChopperAltitude <= 50 and CoordinateDistanceCheck <= 50

then

 

local UnitSetChopperName = UnitSet:GetName()

 

MESSAGE:New(UnitSetChopperName.." has landed on the carrier!",10):ToAll() --This will tell you exactly which unit has landed on the carrier

end

end

)

 

 

Hope this helps!:thumbup:

 

 

EDIT: Actually, you can simply use LAND events to do this (and capture all the relevant EventData that you need), zones and altitude checks aren't even required.

I didn't mention this earlier because I mistakenly assumed that carrier landings didn't generate LAND events (they totally do, fortunately).

I've tested it and works perfectly with choppers and carriers from both coalitions (test mission attached):

 

local ChopperSet = SET_UNIT:New()

:FilterPrefixes("Choppah_") --All choppers in the test mission use this prefix in their ME unit name

:FilterStart()

 

ChopperSet:HandleEvent(EVENTS.Land)

 

function ChopperSet:OnEventLand(EventData)

 

local InitiatorChopperName = EventData.IniUnitName

local InitiatorChopper = UNIT:FindByName(InitiatorChopperName) --This will return the MOOSE unit object of the chopper that initiated the LAND event. I've included it in case you want to do stuff with it after landing

 

local LandingLocationName = EventData.PlaceName --This will return the ME unit name of the carrier involved in the landing event (in this particular case)

 

if LandingLocationName == "Stennis" or LandingLocationName == "Kuznetsov" -- No zones required, the ME unit names of the carriers are enough

then

 

MESSAGE:New(InitiatorChopperName.." has landed on "..LandingLocationName,10):ToAll() --This message will show both the unit name of the initiator chopper and the unit name of the carrier it landed on

 

Stuff you want done when the landing event happens

 

end

end

 

Nice script HardCard, however I think that your script suffers from the same issue I have. Look at the attached picture. I am trying to land on the top of those containers (the green circle). If I fly with the chopper parallel to the ship while in approach (check the blue chopper), the "needed" distance between the center of the ship and the chopper could be respected ...as well as the speed and altitude for the "LANDED" trigger to kick in.

 

While I was testing this I was like "yeah but it should rarely happen that all 3 conditions would be met while flying parallel to the ship". But I was wrong, it happened to me twice only while testing the mission.

 

Maybe there is something to do with the "offset" value in the ZONE_UNIT call.

 

At some point you are talking about a "tiny trigger that can be contained on the deck" ... but I thought that a moving trigger could not be placed on the deck ... but rather always centered on the ship center? Am I missing something?

1559285882_boatlanding.JPG.094ce3554893cd13108d951741f2607b.JPG


Edited by Frag
Link to comment
Share on other sites

@Delta99

 

Thanks man! It took me a while to realize that LAND events could be used for this :D

 

 

@Frag

 

Loved your helicopter doodle ;)

 

Do you want to land on a carrier or on a cargo container placed on the bow of a non-landable ship? We're talking oranges and apples here.

 

For carrier landings, use the last script that I wrote (the one that uses LAND events).

No zones required, the script will work as long as the choppers land on a carrier's deck, it's pretty neat.

 

 

Now, regarding the experimental landing from the picture, I don't even know if that will generate a LAND event (I doubt it very much). If it does, then you'll simply need to include the unit name of that ship in the script.

If it doesn't (which is likely), then we'll need to get creative :juggle:

 

You could get the POINT_VEC2 from that Yakushev cargo ship by using :GetPointVec2() , then modify its position, so it would be located on those containers.

 

If I were you, I'd try the following:

 

- Get the ship's POINT_VEC2

 

- Find out what's the exact altitude of the containers by landing on them and then checking your altitude (for instance).

While you're at it, use a script that returns the following information (via text message):

 

#Ship's POINT_VEC2 X value (use :GetX() for this)

 

#Ship's POINT_VEC2 Y value (use :GetY() for this)

 

 

#Chopper's POINT_VEC2 X value (use :GetX() for this. Take the reading while landed on the containers)

 

#Chopper's POINT_VEC2 Y value (use :GetY() for this. Take the reading while landed on the containers)

 

 

- With the information gathered above, you should be able to calculate the correct offset for the ship's POINT_VEC2

 

 

- Use :AddX() and :AddY() to set the correct offset for the ship's POINT_VEC2.

 

 

- Use :AddAlt() to set the right altitude for the ship's POINT_VEC2.

 

 

- Now you should be able to use :Get2DDistance() in order to find the distance between the ship's customized POINT_VEC2 and the chopper's coordinate.

This should be enough for landing detection, without the need for zones or altitude checks.

 

 

Keep in mind that this method isn't perfect. In order for it to work, the cargo ship must be either static or moving in a straight line... it mustn't be allowed to turn, otherwise all hell will break loose :devil_2:

 

Our custom offset won't "turn with the ship", it'll remain in the same position relative to the map, that's the problem (I mean, a 180º turn should be easy enough to handle, but anything else would be more complicated to calculate).

 

In order for the offset to "turn with the ship", fancy maths must be used... this is beyond my current skills, I need to do some :book: >> :shocking: >> :book: >> :wallbash: >> :book: >> :doh: >> :thumbup: >> :smartass:


Edited by Hardcard
Link to comment
Share on other sites

@Delta99

 

Thanks man! It took me a while to realize that LAND events could be used for this :D

 

 

@Frag

 

Loved your helicopter doodle ;)

 

Do you want to land on a carrier or on a cargo container placed on the bow of a non-landable ship? We're talking oranges and apples here.

 

For carrier landings, use the last script that I wrote (the one that uses LAND events).

No zones required, the script will work as long as the choppers land on a carrier's deck, it's pretty neat.

 

 

Now, regarding the experimental landing from the picture, I don't even know if that will generate a LAND event (I doubt it very much). If it does, then you'll simply need to include the unit name of that ship in the script.

If it doesn't (which is likely), then we'll need to get creative :juggle:

 

You could get the POINT_VEC2 from that Yakushev cargo ship by using :GetPointVec2() , then modify its position, so it would be located on those containers.

 

If I were you, I'd try the following:

 

- Get the ship's POINT_VEC2

 

- Find out what's the exact altitude of the containers by landing on them and then checking your altitude (for instance).

While you're at it, use a script that returns the following information (via text message):

 

#Ship's POINT_VEC2 X value (use :GetX() for this)

 

#Ship's POINT_VEC2 Y value (use :GetY() for this)

 

 

#Chopper's POINT_VEC2 X value (use :GetX() for this. Take the reading while landed on the containers)

 

#Chopper's POINT_VEC2 Y value (use :GetY() for this. Take the reading while landed on the containers)

 

 

- With the information gathered above, you should be able to calculate the correct offset for the ship's POINT_VEC2

 

 

- Use :AddX() and :AddY() to set the correct offset for the ship's POINT_VEC2.

 

 

- Use :AddAlt() to set the right altitude for the ship's POINT_VEC2.

 

 

- Now you should be able to use :Get2DDistance() in order to find the distance between the ship's customized POINT_VEC2 and the chopper's coordinate.

This should be enough for landing detection, without the need for zones or altitude checks.

 

 

Keep in mind that this method isn't perfect. In order for it to work, the cargo ship must be either static or moving in a straight line... it mustn't be allowed to turn, otherwise all hell will break loose :devil_2:

 

Our custom offset won't "turn with the ship", it'll remain in the same position relative to the map, that's the problem (I mean, a 180º turn should be easy enough to handle, but anything else would be more complicated to calculate).

 

In order for the offset to "turn with the ship", fancy maths must be used... this is beyond my current skills, I need to do some :book: >> :shocking: >> :book: >> :wallbash: >> :book: >> :doh: >> :thumbup: >> :smartass:

 

Hey thanks for the new carrier landing tips you added. I was not even aware of the existence of that event! Just saved us a lot of tweaking here!

 

Now as far as my emergency landing on a cargo ship goes ... your vectors idea is top notch! This is a very good idea and I played with those a lot recently in another mission I did. So I am quite used to handled those. Don't even know why I did not think about it in the first place. Having a cargo ship going straight will not be a problem in 90% of the mission so I like the idea A LOT.

 

I will come back here with my final solution for sure. Thanks Hardcard! I promise you more doodle schema in 2019 ;)


Edited by Frag
Link to comment
Share on other sites

Yep my head went right to the Land event followed by a getcoord and check if it's in zone and you are done, no need to be complex for just that.

 

Do you think the land event would work on a ship that is not a carrier? (Sorry I am away from my DCS computer right now so I can't test it, but you tickled my curiosity:) Check post #4, I am doing an emergency landing on a cargo ship.


Edited by Frag
Link to comment
Share on other sites

Do you think the land event would work on a ship that is not a carrier?

 

No harm in trying!

 

Anyway, I've finally figured it out, so you don't need to worry about that anymore!

 

After a few days of study + trial & error, I can finally see the matrix :matrix:

(DCS uses a 3x3 matrix to perform transformations)

 

I've learned quite a lot about how vectors and positioning work in DCS, might write a tutorial about it (or even create a YT tutorial :music_whistling:).

 

Long story short, our cargo ship is using orientation vectors in order to turn, these are actually sines and cosines of its heading. EDIT: Well, not quite, things are more complicated than this!

 

In DCS, the Caucasus map has 3 axes (centered at a point on the Crimean Peninsula).

These 3 axes define the POSITION of objects on the map, but not their ORIENTATION.

 

Map's X axis = South(-) , North(+)

Map's Y axis = Ground(-) , Sky(+)

Map's Z axis = West(-) , East(+)

 

For object orientation relative to these "map axes", each object in DCS relies on its own set of 3 orientation vectors.

 

This is the format of the Lua orientation table that DCS uses for objects (keep in mind that Vec3 is a vector table itself. So this table actually contains 3 different tables):

[color="Blue"]-- Simplified form[/color]
Orientation = {x = Vec3, y = Vec3, z = Vec3}

[color="Blue"]-- Full form (example of ship's rotation around Y axis, values range from -1 to 1)[/color]
Orientation = {
  x = { x = cosine of ship's heading, y = 0, z = sine of ship's heading},
  y = { x = 0, y = 1, z = 0},
  z = { x = negative sine of ship's heading, y = 0, z = cosine of ship's heading}
}

 

EDIT: This is just an approximation, things in DCS are more complicated than this!

 

 

This is basically a 3x3 transform matrix (in this case, it's a rotation matrix around the Y axis).

 

Thanks to this realization, I immediately understood the practical difference between orientation vectors and position vectors in DCS.

 

 

Anyway, here's the solution to the offset landing point problem:

 

#1 First, point the ship to the map's North (heading 0).

Once that's done, find the X and Y position values for the offset landing point (you can either use the ruler tool in ME or actually land on the containers and get the position readings via script. You can use :GetPointVec3() for this)

 

 

#2 With the ship still pointing North, get its X, Y and Z position values (You can use :GetPointVec3() for this)

 

 

#3 Now subtract the ship's X and Y values from the landing point's X and Y values, in order to get the relevant offsets for the transformation.

The Z offset isn't needed for this. It's 0 anyway, since both points are located at 0 Z (the ship's Z orientation axis, that is).

 

 

#4 Now that you have the correct offsets, it's trigonometry time! :yay:

 

Offset_X = The offset value for X * cosine of the ship's heading

Offset_Y = The offset value for Y -- We don't need to do anything fancy here, since the ship only moves along the map's X and Z axes (unless Godzilla decides to make an appearance :D )

Offset_Z = The offset value for X * sine of the ship's heading -- Yes, we need to use the offset value of X here too, but we multiply it by the sine of the heading instead!

 

EDIT: Again, this is just an approximation!

Instead of using the heading's sine and cosine, it's better to use the values from the Position3 table itself (for a ship, we only need to get Position.x.x and Position.x.z)

 

#5 Now we need to add the "transform offsets" to the ship's PointVec3 that we used earlier.

 

LandingPoint_X = Ship's PointVec3 X value + Offset_X

LandingPoint_Y = Ship's PointVec3 Y value + Offset_Y

LandingPoint_Z = Ship's PointVec3 Z value + Offset_Z

 

The ship's PointVec3 has now become our new offset landing point, which will "turn with the ship" :thumbup:

 

#6 Use :Get3DDistance() to get the distance between our offset landing point and the chopper's PointVec3. This will enable us to set up the landing logic.

 

 

I've attached a demo mission + script, so you can see all this stuff in action

 

Here's the script:

 

 

SCHEDULER:New( nil,

function()

 

local CargoHeading = UNIT:FindByName("Cargo"):GetHeading() -- Everything is based on the ship's heading, so we get it

 

local CargoHeadingRadians = math.rad(CargoHeading) -- We need to convert the ship's heading to radians, since the math library in Lua only accepts radians to calculate sines and cosines

 

local CosHeadingRad = math.cos(CargoHeadingRadians) -- The cosine of the ship's heading will determine the X component (South - North) of our offset landing vector

local SinHeadingRad = math.sin(CargoHeadingRadians) -- The sine of the ship's heading will determine the Z component (West - East) of our offset landing vector

 

-- 23.5 is the approximate distance between the cargo ship's center and the containers you want to land on (along the ship's X axis). That's going to be the offset for our landing point

local OffsetX = CosHeadingRad * 23.5 -- This sets the offset for the X component (South -> North) of our landing vector

local OffsetZ = SinHeadingRad * 23.5 -- This sets the offset for the Z component (West -> East) of our landing vector

 

-- Next, we get the ship's center coordinates relative to the map's X, Y and Z axis by using :GetPointVec3()

-- Then we add our "special" offsets to the X and Z components (South -> North and West -> East)

-- The Y component will stay the same all the time, since the ship doesn't fly, so we can set the Y offset the old fashioned way (I've set it to 5 meters)

 

local CargoPointVec3Modified = UNIT:FindByName("Cargo"):GetPointVec3():AddX(OffsetX):AddY(5):AddZ(OffsetZ)

 

-- Now, to confirm that the point is where we want it to be at all times (regardless of the ship's orientation), we make it launch a red flare to signal its position

CargoPointVec3Modified:FlareRed()

 

-- With this, we've taken care of the hardest part of the problem, congratulations!

 

-- Now we can finally set up our container landing detection, we can use a simple coordinate distance check for this

 

local ChopperPointVec3 = UNIT:FindByName("Choppah_Huey"):GetPointVec3() -- Get the PointVec3 of the relevant chopper

 

local LandingDistance = CargoPointVec3Modified:Get3DDistance(ChopperPointVec3) -- Get the distance between our offset landing point and the chopper's PointVec3

 

MESSAGE:New("Huey's distance from offset landing point = "..LandingDistance,1,nil,true):ToAll()

 

if LandingDistance <= 2 -- We can constrain the landing distance to 2 meters, for instance

then

MESSAGE:New("Huey has landed!",1,nil,true):ToAll()

end

 

end,

{}, 0, 1

)

 

 

 

I REALLY hope that you'll find this useful! :thumbup:

Cargo offset landing point test.miz

Cargo offset point test.lua


Edited by Hardcard
Link to comment
Share on other sites

No harm in trying!

 

Anyway, I've finally figured it out, so you don't need to worry about that anymore!

 

After a few days of study + trial & error, I can finally see the matrix :matrix:

(DCS uses a 3x3 matrix to perform transformations)

 

I've learned quite a lot about how vectors and positioning work in DCS, might write a tutorial about it (or even create a YT tutorial :music_whistling:).

 

Long story short, our cargo ship is using orientation vectors in order to turn, these are actually sines and cosines of its heading.

 

In DCS, the Caucasus map has 3 axes (centered at a point on the Crimean Peninsula).

These 3 axes define the POSITION of objects on the map, but not their ORIENTATION.

 

Map's X axis = South(-) , North(+)

Map's Y axis = Ground(-) , Sky(+)

Map's Z axis = West(-) , East(+)

 

For object orientation relative to these "map axes", each object in DCS relies on its own set of 3 orientation vectors.

 

This is the format of the Lua orientation table that DCS uses for objects (keep in mind that Vec3 is a vector table itself. So this table actually contains 3 different tables):

[color="Blue"]-- Simplified form[/color]
Orientation = {x = Vec3, y = Vec3, z = Vec3}

[color="Blue"]-- Full form (example of ship's rotation around Y axis, values range from -1 to 1)[/color]
Orientation = {
  x = { x = cosine of ship's heading, y = 0, z = sine of ship's heading},
  y = { x = 0, y = 1, z = 0},
  z = { x = negative sine of ship's heading, y = 0, z = cosine of ship's heading}
}

 

This is basically a 3x3 transform matrix (in this case, it's a rotation matrix around the Y axis).

 

Thanks to this realization, I immediately understood the practical difference between orientation vectors and position vectors in DCS.

 

 

Anyway, here's the solution to the offset landing point problem:

 

#1 Find the X, Y and Z position values for the offset landing point (you can either use the ruler tool in ME or actually land on the containers and get the position readings via script. You can use :GetPointVec3() for this)

 

 

#2 Get the X, Y and Z position values of the cargo ship (You can use :GetPointVec3() for this)

 

 

#3 Subtract the ship's X, Y and Z values from the offset X, Y and Z values, in order to get your offsets for each position component.

 

 

#4 Now that you have the correct offsets, it's trigonometry time! :yay:

 

Offset_X = The offset value for X * cosine of the ship's heading

Offset_Y = The offset value for Y -- We don't need to do anything fancy here, since the ship only moves along the map's X and Z axes (unless Godzilla decides to make an appearance :D )

Offset_Z = The offset value for Z * sine of the ship's heading

 

 

#5 Now we need to add the "transform offsets" to the ship's PointVec3 that we used earlier.

 

LandingPoint_X = Ship's PointVec3 X value + Offset_X

LandingPoint_Y = Offset_Y

LandingPoint_Z = Ship's PointVec3 Z value + Offset_Z

 

The ship's PointVec3 has now become our new offset landing point, which will "turn with the ship" :thumbup:

 

#6 Use :Get3DDistance() to get the distance between our offset landing point and the chopper's PointVec3. This will enable us to set up the landing logic.

 

 

I've attached a demo mission + script, so you can see all this stuff in action

 

Here's the script:

 

 

SCHEDULER:New( nil,

function()

 

local CargoHeading = UNIT:FindByName("Cargo"):GetHeading() -- Everything is based on the ship's heading, so we get it

 

local CargoHeadingRadians = math.rad (CargoHeading) -- We need to convert the ship's heading to radians, since the math library in Lua only accepts radians to calculate sines and cosines

 

local CosHeadingRad = math.cos(CargoHeadingRadians) -- The cosine of the ship's heading will determine the X component (South - North) of our offset landing vector

local SinHeadingRad = math.sin(CargoHeadingRadians) -- The sine of the ship's heading will determine the Z component (West - East) of our offset landing vector

 

-- 23.5 is the approximate distance between the cargo ship's center and the containers you want to land on. That's going to be the offset for our landing point

local OffsetX = CosHeadingRad * 23.5 -- This sets the offset for the X component (South -> North) of our landing vector

local OffsetZ = SinHeadingRad * 23.5 -- This sets the offset for the Z component (West -> East) of our landing vector

 

-- Next, we get the ship's center coordinates relative to the map's X, Y and Z axis by using :GetPointVec3()

-- Then we add our "special" offsets to the X and Z components (South -> North and West -> East)

-- The Y component will stay the same all the time, since the ship doesn't fly, so we can set the Y offset the old fashioned way (I've set it to 5 meters)

 

local CargoPointVec3Modified = UNIT:FindByName("Cargo"):GetPointVec3():AddX(OffsetX):AddY(5):AddZ(OffsetZ)

 

-- Now, to confirm that the point is where we want it to be at all times (regardless of the ship's orientation), we make it launch a red flare to signal its position

CargoPointVec3Modified:FlareRed()

 

-- With this, we've taken care of the hardest part of the problem, congratulations!

 

-- Now we can finally set up our container landing detection, we can use a simple coordinate distance check for this

 

local ChopperPointVec3 = UNIT:FindByName("Choppah_Huey"):GetPointVec3() -- Get the PointVec3 of the relevant chopper

 

local LandingDistance = CargoPointVec3Modified:Get3DDistance(ChopperPointVec3) -- Get the distance between our offset landing point and the chopper's PointVec3

 

MESSAGE:New("Huey's distance from offset landing point = "..LandingDistance,1,nil,true):ToAll()

 

if LandingDistance <= 2 -- We can constrain the landing distance to 2 meters, for instance

then

MESSAGE:New("Huey has landed!",1,nil):ToAll()

end

 

end,

{}, 0, 1

)

 

 

 

I REALLY hope that you'll find this useful! :thumbup:

 

This is pure gold ... you really nailed it. Actually that logic can be use with a lot of stuff ....not only landing. I had a good idea how to do it following your post of January 13th, but you did all the work! Thanks a thousand time I was not expecting that much :) I owe you a beer.

 

I will try out your script and release that nice mission soon. It has custom sounds/music/scripts and it is quite fun and challenging. I will make sure to give you some credit man. I really appreciate your help.

Link to comment
Share on other sites

What are the chances I'm sitting here at 1am wondering how to do this, searching the forums, and this was posted literally today (errr, yesterday... but feels like today). Pure gold is an understatement, I owe you a keg of beer. THANK YOU!

TM Warthog, Oculus Rift, Win10...

Link to comment
Share on other sites

@Frag

@Sickdog

 

Hi guys!

 

Glad I could help!

 

Truth is that I encountered this problem months ago, I've been wanting to solve it ever since.

 

When Frag suggested that he wanted a customized offset landing point (which, ideally, should be turning with the ship), I decided it was time to find the solution :book:

 

Btw, the script I provided works, but the explanation from my post was partly incorrect.

I edited the post to correct some things, now it should describe what the script does more accurately. :thumbup:

 

Next step is figuring out how to do this with planes, for instance (handling rotations around Z and X).

 

 

-- Taking the 3x3 transform matrix from before (rotation around Y), my guess is that the y table represents the y axis transforms

 

Rotation_Y = {

x = { x = cosine of ship's heading, y = 0, z = sine of ship's heading },

y = { x = 0, y = 1, z = 0 },

z = { x = negative sine of ship's heading, y = 0, z = cosine of ship's heading }

}

 

-- My initial guess is that DCS uses the following 3x3 table/matrix for rotation around the Z axis:

 

Rotation_Z = {

x = { x = cosine of angle, y = negative sine of angle, z = 0 },

y = { x = sine of angle, y = cosine of angle, z = 0 },

z = { x = 0, y = 0, z = 1 }

}

 

The problem is that I don't know yet what's the angle it needs... perhaps it's the AoA, or something like that

 

 

Finally, I guess that rotations around the X axis are handled by the following table/matrix:

 

Rotation_X = {

x = { x = 1, y = 0, z = 0 },

y = { x = 0, y = cosine of angle, z = negative sine of angle },

z = { x = 0, y = sine of angle, z = cosine of angle }

}

 

Again, I don't know yet what's the required angle... perhaps it's the bank angle, or something like that

 

 

 

 

EDIT: Some of the guesses in the spoiler are incorrect, others are simply approximations... Need to keep digging! :book:


Edited by Hardcard
Link to comment
Share on other sites

While I still have your attention, Hardcore, any hints on how to make this work without MOOSE/MIST? I’m working on a script where I need to do this without the aid of those Script tools, fiddled with it a bunch last night but couldn’t get it to work. I would think it should still be possible as the only method I need to do by hand is the GetPointVec3 where you add the offsets.

 

Thanks in advance!

TM Warthog, Oculus Rift, Win10...

Link to comment
Share on other sites

@Frag

@Sickdog

 

Ok guys, after a few hours trying to figure out how to apply this to the Huey, I've realized that my method is a mere approximation :doh:

Looks like I'm only seeing part of the picture...:cry:

 

Fear not, the method will work with ships just fine, in fact, I've found a simpler way to implement it, without the need to calculate sines and cosines (DCS does that automatically, through the 3x3 orientation matrix).

 

I swear, sometimes my brain refuses to see the obvious :megalol:

 

I'll modify my post once again, so there are no misunderstandings.

 

Now, instead of calculating the sine and cosine of the heading angle, you can obtain the precise values by reading from the 3x3 transform matrix directly (hopefully this will also answer Sickdog's questions) :

 

 

-- MOOSE isn't required to access the transform matrix of the object, you can just get the DCSObject and work with standard DCS scripting engine functions (if you want to)

-- You don't need to read from the whole Position3 table to manage the landing offset point, but I'll show you how to access each component, just so you know

 

 

local CargoPosition = UNIT:FindByName("Cargo"):GetDCSObject():getPosition() -- Get the DCSObject and then use standard DCS :getPosition() to get the full position + orientation matrix table (aka Position3)

 

-- CargoPosition.p.x , CargoPosition.p.y and CargoPosition.p.z are the object's position "coordinates" on the map. The three elements of the Position3.p table

 

local CargoPX = CargoPosition.p.x -- X component of the object's position Vec3 relative to the map origin (Crimea)

local CargoPY = CargoPosition.p.y -- Y component of the object's position Vec3 relative to the map origin (Crimea)

local CargoPZ = CargoPosition.p.z -- Z component of the object's position Vec3 relative to the map origin (Crimea)

 

-- Here's the 3x3 orientation matrix itself, it's composed of 3 different tables (x, y and z). Each of these tables contains 3 variables (also called x, y and z):

 

local CargoXX = CargoPosition.x.x -- X component of the object's X Vec3 (the unit's front vector). We'll need this one for our offset landing point

local CargoXY = CargoPosition.x.y -- Y component of the object's X Vec3 (the unit's front vector)

local CargoXZ = CargoPosition.x.z -- Z component of the object's X Vec3 (the unit's front vector). We'll also need this one for our offset landing point

 

local CargoYX = CargoPosition.y.x -- X component of the object's Y Vec3 (the unit's top vector)

local CargoYY = CargoPosition.y.y -- Y component of the object's Y Vec3 (the unit's top vector)

local CargoYZ = CargoPosition.y.z -- Z component of the object's Y Vec3 (the unit's top vector)

 

local CargoZX = CargoPosition.z.x -- X component of the object's Z Vec3 (the unit's side vector)

local CargoZY = CargoPosition.z.y -- Y component of the object's Z Vec3 (the unit's side vector)

local CargoZZ = CargoPosition.z.z -- Z component of the object's Z Vec3 (the unit's side vector)

 

-- Ok, so now that you know how to access the Position3 table, you can use its individual components to create the "dynamic offsets"

 

-- For our offset landing point, we'll only need CargoPosition.x.x and CargoPosition.x.z, no heading, sines or cosines needed

 

local OffsetX = CargoXX * 23.5

local OffsetZ = CargoXZ * 23.5

 

-- Then we simply add the offsets to the ship's PointVec3, like we did before. This can also be done using standard DCS functions, ofc, no need to use MOOSE

 

local CargoPointVec3Modified = UNIT:FindByName("Cargo"):GetPointVec3():AddX(OffsetX):AddY(5):AddZ(OffsetZ)

 

--Done!

 


Edited by Hardcard
Link to comment
Share on other sites

@Frag

@Sickdog

 

Ok guys, after a few hours trying to figure out how to apply this to the Huey, I've realized that my method is a mere approximation :doh:

Looks like I'm only seeing part of the picture...:cry:

 

Fear not, the method will work with ships just fine, in fact, I've found a simpler way to implement it, without the need to calculate sines and cosines (DCS does that automatically, through the 3x3 orientation matrix).

 

I swear, sometimes my brain refuses to see the obvious :megalol:

 

I'll modify my post once again, so there are no misunderstandings.

 

Now, instead of calculating the sine and cosine of the heading angle, you can obtain the precise values by reading from the 3x3 transform matrix directly (hopefully this will also answer Sickdog's questions) :

 

 

-- MOOSE isn't required to access the transform matrix of the object, you can just get the DCSObject and work with standard DCS scripting engine functions (if you want to)

-- You don't need to read from the whole Position3 table to manage the landing offset point, but I'll show you how to access each component, just so you know

 

 

local CargoPosition = UNIT:FindByName("Cargo"):GetDCSObject():getPosition() -- Get the DCSObject and then use standard DCS :getPosition() to get the full position + orientation matrix table (aka Position3)

 

-- CargoPosition.p.x , CargoPosition.p.y and CargoPosition.p.z are the object's position "coordinates" on the map. The three elements of the Position3.p table

 

local CargoPX = CargoPosition.p.x -- X component of the object's position Vec3 relative to the map origin (Crimea)

local CargoPY = CargoPosition.p.y -- Y component of the object's position Vec3 relative to the map origin (Crimea)

local CargoPZ = CargoPosition.p.z -- Z component of the object's position Vec3 relative to the map origin (Crimea)

 

-- Here's the 3x3 orientation matrix itself, it's composed of 3 different tables (x, y and z). Each of these tables contains 3 variables (also called x, y and z):

 

local CargoXX = CargoPosition.x.x -- X component of the object's X Vec3 (the unit's front vector). We'll need this one for our offset landing point

local CargoXY = CargoPosition.x.y -- Y component of the object's X Vec3 (the unit's front vector)

local CargoXZ = CargoPosition.x.z -- Z component of the object's X Vec3 (the unit's front vector). We'll also need this one for our offset landing point

 

local CargoYX = CargoPosition.y.x -- X component of the object's Y Vec3 (the unit's top vector)

local CargoYY = CargoPosition.y.y -- Y component of the object's Y Vec3 (the unit's top vector)

local CargoYZ = CargoPosition.y.z -- Z component of the object's Y Vec3 (the unit's top vector)

 

local CargoZX = CargoPosition.z.x -- X component of the object's Z Vec3 (the unit's side vector)

local CargoZY = CargoPosition.z.y -- Y component of the object's Z Vec3 (the unit's side vector)

local CargoZZ = CargoPosition.z.z -- Z component of the object's Z Vec3 (the unit's side vector)

 

-- Ok, so now that you know how to access the Position3 table, you can use its individual components to create the "dynamic offsets"

 

-- For our offset landing point, we'll only need CargoPosition.x.x and CargoPosition.x.z, no heading, sines or cosines needed

 

local OffsetX = CargoXX * 23.5

local OffsetZ = CargoXZ * 23.5

 

-- Then we simply add the offsets to the ship's PointVec3, like we did before. This can also be done using standard DCS functions, ofc, no need to use MOOSE

 

local CargoPointVec3Modified = UNIT:FindByName("Cargo"):GetPointVec3():AddX(OffsetX):AddY(5):AddZ(OffsetZ)

 

--Done!

 

mmm interesting. Your first script with moose made sense to me since it is basic trigonometry. So I could follow closely. But this new one is Chinese to me. I guess I need to understand the orientation matrix table, which is probably a DCS feature ... I'll go read o the subject.

Link to comment
Share on other sites

Wow, once again I’m really thankful for your explanation and efforts! I’ll try it on my 6 hour flight home tomorrow, nothing like killing time on a flight by scripting!

 

Thanks again Hardcore, I’ll try to revisit here to let you know how it goes.

TM Warthog, Oculus Rift, Win10...

Link to comment
Share on other sites

But this new one is Chinese to me. I guess I need to understand the orientation matrix table, which is probably a DCS feature ... I'll go read o the subject.

 

The orientation matrix uses trigonometric functions to calculate all the values, of that I'm quite convinced.

 

Here's what I've found so far (this will hopefully make more sense):

 

 

- Position.x.x ≈ Cosine of the huey's heading * Cosine of the huey's pitch

 

(It's a pretty good approximation, accurate to 9 figures)

 

Keep in mind that I'm using POSITIONABLE:GetPitch() in order to get the huey's pitch angle.

This MOOSE function simply takes the Position.x.y value from the orientation table and calculates its arc sine (it returns the resulting value in degrees).

 

return math.deg(math.asin(unitpos.x.y))

 

To get the heading, I'm using POSITIONABLE:GetHeading(), which calculates the arc tangent of Position.x.z and Position.x.x

 

PositionableHeading = math.atan2( PositionablePosition.x.z, PositionablePosition.x.x )

 

- Position.x.y = Sine of the huey's pitch

 

Given that POSITIONABLE:GetPitch() uses the arc sine of this value to calculate pitch, it's not surprising to discover that the sine of the pitch is exactly equal to Position.x.y

 

- Position.x.z ≈ Sine of the huey's heading * Cosine of the huey's pitch

 

(Another pretty good approximation, accurate to 9 figures)

 

- Position.y.x = ?

 

This one has refused to yield its secrets so far. My guess was that this should be equal (or pretty close) to the negative sine of the pitch, but it's only marginally close, it's not a match.

 

- Position.y.y = ?

 

This one has also refused to yield its secrets. My best guess was that this should be equal (or pretty close) to the cosine of the pitch, but it's only marginally close...not a match.

 

- Position.y.z = ?

 

It matches none of the sine and cosine combinations I've tried. It must be linked to something else.

 

- Position.z.x = ?

 

The closest value is the negative sine of the heading, but it's only marginally close, it's not a match by any means.

 

- Position.z.y = ?

 

It matches none of the sine and cosine combinations I've tried. It must be linked to something else.

 

- Position.z.z = ?

 

The closest value is the cosine of the heading, but it's only marginally close, it's not a match by any means.

 

 

These might be just lucky coincidences, though, I honestly don't know what's going on.

Perhaps these are the results of multiplying different transformation matrices, that might explain the mismatch between the values.

 

Need to keep digging! :book:


Edited by Hardcard
Link to comment
Share on other sites

Great news, guys!

 

Thanks to funkyfranky's wisdom and expertise, I've learned how to apply this offset trick to all axes!

 

It can be applied to aircraft as well! (I haven't tested it with ground units yet, but it should work)

 

Here's funkyfranky's masterful script:

 

 

local unit=UNIT:FindByName("My Unit")

 

-- Vectors making up the coordinate system.

local X=unit:GetOrientationX()

local Y=unit:GetOrientationY()

local Z=unit:GetOrientationZ()

 

-- Offset vector: 5 m ahead, 4 meters starboard, 3 meters above.

local A={x=5, y=3, z=4}

 

-- Scale components of orthonormal coordinate vectors.

local x={x=X.x*A.x, y=X.y*A.x, z=X.z*A.x}

local y={x=Y.x*A.y, y=Y.y*A.y, z=Y.z*A.y}

local z={x=Z.x*A.z, y=Z.y*A.z, z=Z.z*A.z}

 

-- Add up vectors in the unit coordinate system ==> this gives the offset vector relative the the origin of the map.

local a={x=x.x+y.x+z.x, y=x.y+y.y+z.y, z=x.z+y.z+z.z}

 

-- Vector from the origin of the map to the unit.

local u=unit:GetVec3()

 

-- Translate offset vector from map origin to the unit.

-- v=u+a

local v={x=a.x+u.x, y=a.y+u.y, z=a.z+u.z}

 

-- Get coordinate

local coord=COORDINATE:NewFromVec3(v)

 

-- Flare

coord:FlareRed()

 

 

 

I've rewritten it using variables rather than tables, so it's easier to understand (hopefully).

I've also adapted it to my demo mission:

 

 

SCHEDULER:New( nil,

function()

 

local Cargo = UNIT:FindByName("Cargo")

 

-- Vectors making up the coordinate system.

 

local CargoXX = Cargo:GetOrientationX().x

local CargoXY = Cargo:GetOrientationX().y

local CargoXZ = Cargo:GetOrientationX().z

 

local CargoYX = Cargo:GetOrientationY().x

local CargoYY = Cargo:GetOrientationY().y

local CargoYZ = Cargo:GetOrientationY().z

 

local CargoZX = Cargo:GetOrientationZ().x

local CargoZY = Cargo:GetOrientationZ().y

local CargoZZ = Cargo:GetOrientationZ().z

 

-- Offset vector: 24 m ahead, 5 meters above, 0 meters starboard (variable format)

 

local Offset_X = 24

local Offset_Y = 5

local Offset_Z = 0 -- I've set it to 0 because the cargo containers are aligned with the ship's Z origin

 

-- Scale components (variable format)

 

local Scale_XX = CargoXX * Offset_X

local Scale_XY = CargoXY * Offset_X

local Scale_XZ = CargoXZ * Offset_X

 

local Scale_YX = CargoYX * Offset_Y

local Scale_YY = CargoYY * Offset_Y

local Scale_YZ = CargoYZ * Offset_Y

 

local Scale_ZX = CargoZX * Offset_Z

local Scale_ZY = CargoZY * Offset_Z

local Scale_ZZ = CargoZZ * Offset_Z

 

 

-- Add up the relevant scale components to get the final offset values

 

local Addition_X = Scale_XX + Scale_YX + Scale_ZX

local Addition_Y = Scale_XY + Scale_YY + Scale_ZY

local Addition_Z = Scale_XZ + Scale_YZ + Scale_ZZ

 

-- Get PointVec3 and add up vectors in the unit coordinate system ==> this gives the offset vector relative the the origin of the map (variable format)

 

local Cargo_Offset_PointVec3 = Cargo:GetPointVec3():AddX(Addition_X):AddY(Addition_Y):AddZ(Addition_Z)

 

-- Flare

Cargo_Offset_PointVec3:FlareRed()

 

end,

{}, 0, 1

)

 

 

This little jewel will come in handy indeed! :thumbup:


Edited by Hardcard
Link to comment
Share on other sites

Oh wow, can’t wait to try it, haven’t had a chance yet but looks like good thing I waited! Thanks Hardcore!

 

Edit: So hate to pester you some more, but any idea on how to apply this without using Moose/Mist? I've been playing around with it for an hour with no luck. I've looked at the GetVec3 method to get an idea of what's going on and I'm using the getPosition method with no luck. Here's my code if it helps:

 

 

Edit #2: Never mind, got it! Code below if it helps anyone. AND THANKS AGAIN HARDCORE FOR YOUR HELP!!!

 

oh, and I'm trying to move the position 20m towards the bow, and 20m starboard.

 

 

 

local cvn_pos2 = Group.getByName('CVN'):getUnits()[1]:getPosition()

 

local cvnXX = cvn_pos2.x.x

local cvnXY = cvn_pos2.x.y

local cvnXZ = cvn_pos2.x.z

 

local cvnYX = cvn_pos2.y.x

local cvnYY = cvn_pos2.y.y

local cvnYZ = cvn_pos2.y.z

 

local cvnZX = cvn_pos2.z.x

local cvnZY = cvn_pos2.z.y

local cvnZZ = cvn_pos2.z.z

 

 

local Offset_X = 20

local Offset_Y = 0

local Offset_Z = -20

 

 

 

local Scale_XX = cvnXX * Offset_X

local Scale_XY = cvnXY * Offset_X

local Scale_XZ = cvnXZ * Offset_X

 

local Scale_YX = cvnYX * Offset_Y

local Scale_YY = cvnYY * Offset_Y

local Scale_YZ = cvnYZ * Offset_Y

 

local Scale_ZX = cvnZX * Offset_Z

local Scale_ZY = cvnZY * Offset_Z

local Scale_ZZ = cvnZZ * Offset_Z

 

local Addition_X = Scale_XX + Scale_YX + Scale_ZX

local Addition_Y = Scale_XY + Scale_YY + Scale_ZY

local Addition_Z = Scale_XZ + Scale_YZ + Scale_ZZ

 

local adjusted_cvn_position = cvn_pos2

adjusted_cvn_position.x = cvn_pos.x + Addition_X

adjusted_cvn_position.y = cvn_pos.y + Addition_Y

adjusted_cvn_position.z = cvn_pos.z + Addition_Z

 

 

trigger.action.signalFlare(adjusted_cvn_position, 2, 0)

 


Edited by Sickdog

TM Warthog, Oculus Rift, Win10...

Link to comment
Share on other sites

Oh wow, can’t wait to try it, haven’t had a chance yet but looks like good thing I waited! Thanks Hardcore!

 

 

I swear to God, everytime I read "Hardcore", I roll laughing on my chair LOLLL

 

No mean intend here guys, I guess at this point is no longer a typo ;)

Link to comment
Share on other sites

This is crazy, amazing how your eyes can play tricks on you... this whole time I’ve been seeing your name as “hardcore”, like my eyes start to read it and then my Brain takes over and completes the spelling. Oops! Sorry “Hardcard”! Haha!

TM Warthog, Oculus Rift, Win10...

Link to comment
Share on other sites

@Sickdog

 

Yes, that happens to me too, sometimes. I think it has to do with how our brain "reads" (it has a kind of "auto-correct" built-in).

 

We don't always read every letter in a word, we simply take the word as a whole and compare it to already known word "patterns".

 

If there's a substantial match, our brains assume that the word has been correctly identified and then moves on to the next word.

This all happens in a split second, of course, that's why we don't even realize.

 

Here's a pretty interesting article on the topic, written by a neuroscientist from Cambridge:

https://www.mrc-cbu.cam.ac.uk/people/matt.davis/cmabridge/

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...