Nexus Modding > Scripting

Code improving (check wether a ship is headed towards an object or not)

<< < (2/3) > >>

Arparso:

--- Quote ---And if the readings vary so much, it would either give me false positive or false negatives values.
--- End quote ---
The readings may vary, but they're not wrong. My code snippet above will reliably tell you how much distance was gained or lost between both ships since the last Tick. If you only care about if a ship is coming closer or if it's gaining distance, then that's enough already. You won't get false positives or false negatives.

The varying readings are a direct result of Tick not getting called exactly every 0.5 seconds. There are lots of technical reasons for that... it's just the way the game (and actually PCs in general) works.

Of course, the whole measuring-the-change-in-distance-thing is kinda flawed anyway, because it's not precise enough. It just tells you, if the ship is currently coming any closer or not - but it doesn't tell you anything about it's current course and if it's really headed for that other ship. To know that, you'll need to examine the actual movement vectors... but the question remains, if you really need to do that!?


--- Quote ---On an other, completely unconnected question: is it posible to disable a fighter or commando's engines or other fighter device for that matter?
--- End quote ---
Haven't tested it myself, but should be possible. Once they've undocked, fighters are mostly treated just like any other ship.

Mularac:
It's part of a mission, and this is basically what I'm doing: I take a ship velocity and then compare it to the difference between the distances one second later, if the ship is moving towards the object i used to measure the distance, both readings should be similar (The difference is, in fact, arround 10 or so points lower, but that's pretty constant, regardless of the actual speed). The code works pretty well, and I didn't find a better way of doing... (I did thought of creating a sort of "path" made of navig points with small areas that got updated every second or so, and if the ship got near those areas a warning would be issued, but I dropped as it seemed to be too inefficient and complicated)

The Old Dragon:
Sorry if I muddy the waters here a little, but if you wish to know if you're travelling to or from a known object, why not simply measure the distance?

This seems to do the job to me...

         
--- Code: ---RULE event Tick

:action

Rangeold:=Rangenew;

Debug("Old range is ",rangeold);

Rangenew:=Distance(M.PS,M.ES);
Debug("Distance between ships is ",Rangenew);

If(RangeOld>RangeNew,Debug("Danger! Danger Will Robinson!"));

:end //end action

END //end rule

TICK 3
--- End code ---

Arparso:
Yep, we're already doing that, more or less. However, if you really want to know, if ship A is directly approaching ship B, simple distance measuring isn't going to cut it. Ship A could be headed for a totally different destination and still come a little closer to ship B during its flight.

You could compare the measured distance to the velocity of the ship, to see if close to 100% of its thrust are used to approach ship B... but that assumes you know about the average velocity since the last tick and you can measure time precisely enough to know how much distance the ship should have travelled since the last tick. The first one can be achieved by setting the speed to a specific value and not allowing the player to change it. The second, however, is quite impossible, I fear. At least I don't know a good way to measure time in Nexus - Tick just isn't precise enough, as already shown.

The only reliable way of knowing, wether ship A is approaching ship B would be to have a look at its movement vector like, for example:

--- Code: ---// calculates, if E.ship approaches E.target or departs from it
// returns 1 for approach, -1 for departing or 0 for every other course
RULE event GetShipApproachesShip
    condition IsValid(E.ship)&IsValid(E.target)
    :action
        // return 0, if we don't have a last position value for the ship
        if(E.ship:lastPosition = 0,
            return(0);
            , // else
            // calculate vector from ship to target
            E.targetVector := VNorm(VSub(E.target:position, E.ship:position));
            // calculate actual movement vector of ship
            E.actualVector := VNorm(VSub(E.ship:position, E.ship:lastPosition));
           
            // calculate dot product of both vectors
            // (equals cosine of angle between vectors)
            E.dot := VDot(E.targetVector, E.actualVector);                    
           
            // maximum allowed deviation from perfectly accurate approach/departing
            // lower margin means ships have to fly directly to the target to
            // count as "approaching", higher margin allows for more generous approaches
            E.margin := 0.1;
           
            if(E.dot + E.margin > 1,
                // approaching
                return(1);
                ,
                if(E.dot - E.margin < -1,
                    // departing
                    return(-1);
                    ,
                    // indifferent
                    return(0);
                );
            );
        );
        E.ship:lastPosition := E.ship:position;
    :end
END
--- End code ---

You could use that rule as such:


--- Code: ---TICK 1

RULE event Tick
    :action
        approaching := LocalEvent(GetShipApproachesShip, E.ship:=m.al; E.target:=m.ac);
        if(approaching = 1,
            Debug("Ship approaches target");
        );
    :end
END
--- End code ---

Mularac:
Of course... how didn't I see this before? It seems I'm starting to forget everything I saw in the entry course to college :P
If the vectors are perpendicular, the Vdot will be 0, as it would be the cosenus of 90, but you're also forgetting that the scalar product of two vectors is not only the cosenus of those vectors but also the product of the modules of those vectores, so the answer could very well be higher than 1. Or at least that's what I learned in college about this tipe of operation.
So in orther to make this code comple we will have to add this:


--- Code: ---E.dot := VDot(E.targetVector, E.actualVector)/Vlen(E.targetVector).Vlen( E.actualVector);  

--- End code ---

so it'd be like this:
lets say that e.targetvector=A and e.actualvector=B

the operation would be this:
e.dot=A.B/||A||.||B||=||A||.||B||.Cos(angle formed by A.B)/(||A||.||B||)
so in the end it would be:
e.dot=cos(angle formed by A.B)

Navigation

[0] Message Index

[#] Next page

[*] Previous page

Go to full version