Not signed in (Sign In)

Discussion Tag Cloud

Categories

Vanilla 1.1.9 is a product of Lussumo. More Information: Documentation, Community Support.

    •  
      CommentAuthorBasilisk
    • CommentTimeDec 13th 2016
     
    Does anyone have an attachment script for scenery objects?
    • CommentAuthoriHack97
    • CommentTimeDec 19th 2016 edited
     
    Is it possible to return Matrix4x4f on a keyframe animation?
    •  
      CommentAuthorbestdani
    • CommentTimeDec 19th 2016
     
    NL2-Manual - Scripting API - Class SceneObjectElement - getMatrix() / getAbsoluteMatrix()Behaviour is undefined when using key frame animation playback.
    •  
      CommentAuthorFüchschen
    • CommentTimeDec 19th 2016 edited
     
    i wanted to try out loading files from ressourceIDs, but it didnt work as expected:

    String config = com.nolimitscoaster.Tools.loadTextFile("config/menu_mainButton.txt");
    System.out.println(config);
    // OUTPUT: test

    String config = com.nolimitscoaster.Tools.loadTextFileFromRessourceID("CONFIG_mainButton"); //using com.nolimitscoaster because sometimes it cant
    find them, when i import classes. Just to root out additional problems.
    System.out.println(config);
    // OUTPUT: null

    Using the ressource IDs would really help, because i could use one script in many different ways. :>

    ...

    My question is: where is the file located, when i use the Ressource ID?
    At the position, where the NL2ScriptDescription (nl2script) is located, right?

    The (.nl2script) and the (.sco) are located in the same folder, so it wouldnt matter, if they use the script-file or the object-files anyway.
  1.  
    So I was testing the attachment script today and it works. My question is since it picks up on the scene object closest to the train what do ya do it you have a custom station? How do you tell it which object to pick, if that's possible.
    •  
      CommentAuthorFüchschen
    • CommentTimeDec 19th 2016 edited
     
    ^
    You can give the target-SCO a name and then let the script look for that name.

    it would work like this: sco name attachment
    You might need to post your script and maybe i can add the script to it.

    The class that i used in the video is huge and im not sure, what you need from it.
  2.  
    Does creating cable lifts with Nolimitsframework still work properly? I've been following geforcefan's tutorial exactly, and it doesn't seem to be working.
  3.  
    ^^ Its just the attach object script from the NL2 Resources Thread.

    import com.nolimitscoaster.*;
    import nlvm.math3d.*;

    /* **************************************************************************
    This is a generic object attachment script.

    Directions to use this script.
    1) Copy and paste attach_object.nlvm to the same directory as your .nl2sco file.
    2) Open the NL2SCO Editor and go to the Scripts tab.
    3) Select attach_object.nlvm from the Script Class dialog.
    4) Save the file and Refresh the scene object.

    View the in-game Help for creating .nl2sco files for your 3D models.

    It is unlikely that your object will be positioned exactly where you want it at first.
    You can modify the positional offset off the 3D model by adding or subtracting
    from xOffset, yOffset, zOffset below.
    *************************************************************************** */


    public class attach_object extends Script
    {
    // ====== CUSTOMIZABLE VARIABLES =======
    // Note: Decimal point "float" values must be followed by an 'f' (e.g. 0.5f, -9.205f). Whole values do not need the 'f'.
    private static final float xOffset = 0; // left/right
    private static final float yOffset = 0.75f; //up/down
    private static final float zOffset = 0.5f; //back/forth
    private static final float range = 5; // The first train within this range of the scene object will receive the attachment. (range is in meters)
    private static final int carToAttach = 0; // Defines the car on the train that will receive the attachment. (0 = lead car or zero car)
    // ======================================

    private SceneObject sco; // Scenery object handle.
    private Train train; // Train handle.
    private Vector3f posOut = new Vector3f(0,0,0); // Will store the scenery object's position based on the car's position.
    private Vector3f pitchHeadBankOut = new Vector3f(0,0,0); // Will store the scenery object's orientation based on the car's orientation.
    private Matrix4x4f carMatrix = new Matrix4x4f(); // Will store the car's orientation.

    //**************************************************************************************
    // onInit is called when the scene object is loaded. Use this for initialization.
    // onInit should return true if initialization succeeds, else false.
    // If onInit returns false then the script will be disabled automatically and onNextFrame will never be called.
    //**************************************************************************************
    public bool onInit()
    {
    // ********************************************
    // Get the scene object handle.
    // ********************************************
    sco = sim.getSceneObjectForEntityId(getParentEntityId());
    if (sco == null)
    {
    System.err.println("attach_object.nlvm: This script must be assigned to a scene object.");
    return false;
    }

    // ********************************************
    // Determine if there is a track within range of the scenery object.
    // ********************************************
    TrackPos trackPos = sim.findNearestCoasterTrack(sco.getTranslation(), range);
    if (trackPos == null)
    {
    System.err.println("attach_object.nlvm: No track found within range of " + range + " meters.");
    return false;
    }

    // ********************************************
    // Determine if there is a train within range of the scenery object.
    // ********************************************
    Coaster coaster = trackPos.getCoaster();
    train = coaster.findNearestTrain(sco.getTranslation(), range);
    if (train == null)
    {
    System.err.println("attach_object.nlvm: No train found within range of " + range + " meters.");
    return false;
    }

    return true;
    }

    public void onNextFrame(float tick)
    {
    // ********************************************
    // Obtain the orientation matrix of the last car
    // ********************************************
    train.getCarMatrix(carToAttach, carMatrix);

    // ********************************************
    // Convert the matrix obtained from getCarMatrix()
    // to the Euler angle vector used in setRotation()
    // ********************************************
    Tools.matrixToPitchHeadBankPos(carMatrix, pitchHeadBankOut, posOut);

    // ********************************************
    // Calculate XYZ offset
    // ********************************************
    Matrix4x4f matrix = new Matrix4x4f();
    matrix.initTrans(xOffset, yOffset, zOffset);
    carMatrix.multRight(matrix);

    // ********************************************
    // Update the scene object's rotation and
    // position for this frame.
    // ********************************************
    Tools.matrixToPitchHeadBankPos(carMatrix, pitchHeadBankOut, posOut);
    sco.setRotation(pitchHeadBankOut);
    sco.setTranslation(posOut);
    }
    }

    Where in there would I put the name of the object?
    •  
      CommentAuthorbestdani
    • CommentTimeDec 20th 2016
     
    Posted By: UtahCoasterRiderHow do you tell it which object to pick, if that's possible.

    You assign the script to the scene object that should be hooked to the train, the object selects the train and not vice versa, therefore it should not be affected by custom stations.
  4.  
    ^ Ah duh cool cool. Thanks
    •  
      CommentAuthorFüchschen
    • CommentTimeDec 22nd 2016 edited
     
    Need a explaination...

    I needed to get rid of \t and \n in a string:


    Why dosn't this work:


    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < len; i++) {
    if (ch[i] != '\t' || ch[i] != '\r' || ch[i] != '\n') {
    sb.append(ch[i]);

    }
    }
    System.out.println(sb);


    But this one does:


    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < len; i++) {
    if (ch[i] == '\t' || ch[i] == '\r' || ch[i] == '\n') {

    }else{
    sb.append(ch[i]);
    }
    }
    System.out.println(sb);


    Its basicly the same, but the first one is shorter (dosnt use "else".) :/
    Was wondering for one hour, why it dosnt work and than i just thought:
    Lets try it with "else" and waste some bytes just for the lols.

    ... and it worked .___.

    PS:
    I used an imported text-file.
    (A HTML File to be specific):


    <!Docktype html>
    <html>
    <head>
    <title>Flash-Fox.de</title>
    <link rel="shortcut icon" href="./header/ff_icon.ico" type="image/x-icon" />
    <body background="ABLAGE/bg/background.jpg" text="#990000" link="#0000CC" vlink="#000066" alink="#000000">
    <meta charset="utf-8">
    <link rel="stylesheet" href="./theme/style.css" type="text/css" />

    <!--
    /* ... Hier werden die Formate definiert ... */
    -->
    </style>
    <!-- google+ erkennungslink -->
    <a href="https://plus.google.com/105985104853682937940" rel="publisher">Google+</a>
    </head>
    <div align="center" >
    <img src="./underDev2.png" alt="Under Development" align="center" width="960" height="768"><br>
    </div>
    </body>
    </html>


    I want to see if its possible, to add Google Adsense to Nolimits.
    Would be nice if some banners and SCOs generate a small amount of money ...

    ... Realistic Parks needs realistic adverts. Otherwise its not a realistic park at all. :D
    (But im sure, it wont work.)




    Another question:
    Casting Object to Array type
    Does this work in nlvm?

    followed this instruction, but it didnt work that well:
    http://stackoverflow.com/questions/1611735/java-casting-object-to-array-type
    I have a Vector (object) with 2 Arrays containing the values.
    •  
      CommentAuthorbestdani
    • CommentTimeDec 23rd 2016
     
    Problem between "||" and "&&":

    !(b0 || b1 || b2) = !b0 && !b1 && !b2
    •  
      CommentAuthorFüchschen
    • CommentTimeDec 23rd 2016 edited
     
    ^
    You always pick the easier one to answer ;P
    But still dont get the exact difference, but ok.


    And for the secound one (Casting Object to Array Type):
    It works, when its split apart.

    Not Working:

    int[] foo= (int[])bar.elementAt(n);


    Working:

    Vector foo= bar; //Or a method, that returns this var.
    int[] foobar= (int[])foo.elementAt(n);


    Hope i did it right (its not copy&pasted -> foo-bar variable names are easier to read)... need coffee.
    But basicly it works when split apart.

    Now i can use Vectors as a road-train in some sort, that transports lots of arrays
    •  
      CommentAuthorbestdani
    • CommentTimeDec 23rd 2016
     
    Posted By: FüchschenBut still dont get the exact difference


    || means OR
    && means AND

    false && false = false
    true && false = false
    true && true = true

    false || false = false
    true || false = true
    true ||true = true


    with OR

    if (ch[i] != '\t' || ch[i] != '\r' || ch[i] != '\n'):

    for example when ch[i] = '\r'
    ch[i] != '\t' -> true
    ch[i] != '\r' -> false
    ch[i] != '\n' -> true

    true || false || true = true

    => if(true) ...
    => char will be appended


    with AND

    if (ch[i] != '\t' && ch[i] != '\r' && ch[i] != '\n'):

    for example when ch[i] = '\r'
    ch[i] != '\t' -> true
    ch[i] != '\r' -> false
    ch[i] != '\n' -> true

    true && false && true = false

    => if(false) ...
    => char will not be appended as desired
    •  
      CommentAuthorFüchschen
    • CommentTimeDec 23rd 2016 edited
     
    ^
    this is the part i can understand.

    But why is:

    if(ch[i] != '\t'){ //false }else{//true}
    if(ch[i] == '\t'){ //false }else{//true}

    != means: Not equal
    == means: equal.

    So how can both be true on the "else" part.

    -------

    I used ||, because it had to be true. I was replaceing empty spacec or newlines or tabs with ''<-nothing.
    That was all intended... just that both are true in the "else" position, even if the equation is different.

    its like this:
    1+1 = 3 (is 3) =====> True / correct
    1+1!= 3 (is not 3) ==> True / correct
    the secound one makes sense, but not the first one (because 1+1 is obviously not 3, so "is not" would be true :D).
    •  
      CommentAuthorbestdani
    • CommentTimeDec 23rd 2016
     
    Posted By: FüchschenBut why is:

    if(ch[i] != '\t'){ //false }else{//true}
    if(ch[i] == '\t'){ //false }else{//true}

    This wasn't the problem and not what happend, the problem was how you combined the not equals. I'll try to break fully down what happened using as an example that char[i] = '\t' now:

    • In the working example you ask:
      if ('\t' == '\t' || '\t' == '\n' || '\t' == '\r')therefore you ask forif (true || false || false). Because the first condition is already true the whole condition is true, the if block will be executed (ok it is empty, thefefore nothing happens).

      The else block would only be executed when the case if(false || false || false) appears.


    • In the not working (because you accidentally made an error as you inverted the condition) example you ask:
      if ('\t' != '\t' || '\t' != '\n' || '\t' != '\r')therefore you ask forif (false || true || true). Because the second and the third conditions are true the whole condition is true, the if block will be executed (and the char will be added - this is not what you wanted).

      The if block would only not be executed in the caseif (false || false || false)(which is impossible because when char[i] is '\t' it cannot be '\n' as well).


    • In the correctly inverted condition you ask:
      if (\'t' != \'t' && '\t' != '\n' && '\t' != '\r')therefore you ask forif (false && true && true). Because the first condition is false the whole condition is false, the if block will not be executed (and the char not be added as desired).

      The if block would only be executed in the caseif (true && true && true) which is the case when the char is 'a' for example.



    I hope I could help you to understand the problem now. I think it's rather hard to explain, that's why I tried it again. ;-)
    •  
      CommentAuthorXpress
    • CommentTimeDec 24th 2016
     
    Looking for some help getting a Full Throttle-esque type launch scripted in. Any suggestions on where I might start looking for answers?
    • CommentAuthoriCoaster44
    • CommentTimeDec 26th 2016
     
    I'm using this code that play a soundtrack outside the train but the sound is really quiet and it only plays in the first car and not the whole train:
    import com.nolimitscoaster.*;
    import nlvm.util.*;

    public class onBoardSound extends Script {
    private static final String sCoastername = "myCoaster";
    private static final String sOnBoardSoundTriggerName = "onBoardMusic";
    private static final String sOnBoardSoundFilename = "onBoardSound";
    Coaster cMyCoaster;

    Vector triggerListeners;

    public bool onInit() {
    cMyCoaster = sim.getCoaster(sCoastername);
    if(cMyCoaster == null) {
    System.err.println("Coaster " + sCoastername + " not found");
    return false;
    }

    TrackTrigger tOnBoardSoundTrigger = cMyCoaster.getTrackTrigger(sOnBoardSoundTriggerName);
    if(tOnBoardSoundTrigger == null) {
    System.err.println("Trigger " + sOnBoardSoundTriggerName + " not found");
    return false;
    }

    int numTrains = cMyCoaster.getTrainCount();
    triggerListeners = new Vector(numTrains);

    for(int i = 0; i < numTrains; i++) {
    onBoardSoundTrigger trigger = new onBoardSoundTrigger();
    trigger.setSound(sOnBoardSoundFilename + i + ".ogg");
    trigger.setTrain(cMyCoaster.getTrainAt(i));
    triggerListeners.addElement(trigger);

    tOnBoardSoundTrigger.addTrackTriggerListener(trigger);
    }

    return true;
    }

    public void onNextFrame(float tick) {
    for(int i = 0; i < triggerListeners.size(); i++) {
    onBoardSoundTrigger trigger = (onBoardSoundTrigger) triggerListeners.elementAt(i);
    trigger.updatePosition();
    }
    }
    }

    import com.nolimitscoaster.*;
    import nlvm.math3d.*;

    public class onBoardSoundTrigger implements TrackTriggerListener {
    private String sSoundFile = "onBoardSound";

    StaticSound sSound;
    Train tCurrentTrain;

    Vector3f vFrontOut;
    Vector3f vTopOut;
    Vector3f vRightOut;
    Vector3f vPosOut;

    public onBoardSoundTrigger() {
    vFrontOut = new Vector3f(0.0f, 0.0f, 0.0f);
    vTopOut = new Vector3f(0.0f, 0.0f, 0.0f);
    vRightOut = new Vector3f(0.0f, 0.0f, 0.0f);
    vPosOut = new Vector3f(0.0f, 0.0f, 0.0f);
    }

    public void setSound(String filename) {
    sSound = StaticSound.loadFromFile(filename, 0);
    if(sSound == null) {
    System.err.println("Sound file not found");
    return;
    }
    sSound.setEnvironmentMode(StaticSound.E_ENVMODE_LOCAL);

    sSound.setGain(1.0f);
    }

    public void setTrain(Train _train) {
    tCurrentTrain = _train;
    }

    public void onTrainEntering(TrackTrigger trigger, Train train) {
    if(train == tCurrentTrain && sSound != null) sSound.play();
    }

    public void onTrainLeaving(TrackTrigger trigger, Train train) {
    }

    public void updatePosition() {
    if(tCurrentTrain == null || sSound == null) return;

    tCurrentTrain.getCarOrientationAndPosition(0, vFrontOut, vTopOut, vRightOut, vPosOut);
    sSound.setPosition(vPosOut);
    }
    }
    from geforcefan
    Please, is there another proper way of doing it ?
  5.  
    Has anyone ever put out a tutorial or overview of scripting a cable lift or a cable launch? I've been looking at scripts from released rides that have them but can't wrap my head around it.
    • CommentAuthorjongscx
    • CommentTimeDec 29th 2016
     
    I'm in the early stages of researching my options on the possibility of NL2 as a debug and simulation tool for programming ride controls. Ultimately, my question is whether NL2 is be able to "run in manual" with all of the brakes and drive wheels being directly commanded to turn on and off, with the plan being that an external PLC would be sending these ON/OFF signals over Ethernet.

    My second question, how can I simulate discrete inputs, more specifically proximity switches? Is there a way to detect collisions IE: I can have a 1 voxel point on the track and it can turn a bit true or false if it is IN the train? If not, I guess I could probably do a:

    if( TrainPos - HalfTrainLength < ProxPos < TrainPos + HalfTrainLength)
    { ProxA = true;
    }
    Else
    { ProxA = false;
    }


    I'd prefer the collision as I would also need to do the same for queue gates and track switches. Is there a better way I'm not thinking about?
    (Ideally, it would be something a simple as adding a track divider and I can pick from the dropdown if it senses the brake fin, magnet yoke, etc. and what bit on the ethernet word it's flipping)

    Lastly, is this even something for community or should I be contacting the creator instead? I understand that nothing in life is free and I am willing to consider that this is more in the realm of paid custom software development.
    •  
      CommentAuthorbestdani
    • CommentTimeDec 30th 2016
     
    You can control the brake and wheel devices to some limited extent, there are also track triggers implemented which could be used as approximate switches but not to such a high level detail that you requested, but there are maybe workarounds for this. Also for receiving data over ethernet, there's is a telemetry server included in NL2 but it cannot communicate with the scripts currently, I can currently just imagine a rather inconvenient way how this could be achieved by using the telemetry server or by having a seperate program that communicates with a NL2 by writing in files that the NL2 scripts can read. The latter worked rather good in a quick test by me but I would be careful using that for some productive environment.

    As far as I know you can test the scritping features in the Demo version already (It sounds as if you don't have NL2 already?) but contacting the NL2 team for details would probably be the best advice since it is no secret that they also offer special versions and support for professionals.
  6.  
    I would like to attach sound to objects that is triggered by a train passing a trigger, yet when I search for a script that does this I always find onride audio scripts. Does anyone know where I could find a skript for offride triggered audio?
    • CommentAuthorTOGO Fan
    • CommentTimeDec 30th 2016
     
    Can a scripted flying eagles ride be able to be snapped in the simulation? TheCodeMaster is making one.
    •  
      CommentAuthorFüchschen
    • CommentTimeJan 5th 2017 edited
     
    Is there some way, to make this a bit shorter?

    Shader core

    //Dynamic Entity color & negative alpha map of textur unit 0
    tmp0 = Entity0;
    tmp0.a = sub(1,Tex0.a);

    //interpolate between 'Entity Color' and 'Tex0'
    tmp2 = Lerp(tmp0.a, tmp0 , tex0);

    Result = tmp2;
    Result.a = 1; //Result.a = 1, because you dont want holes in your object.

    A year befor, we could just do something like this to add a transparent picture on a base texture:
    add(Entity0, Tex0);
    but now it results in Minecraft Textures (huge block-like pixels), because there seem to be no blending in place.
    This is why i added each half of the alpha map and interpolate them together... i think ... :>


    In words:
    for example: you have a block break (object) that can be dynamicly recolored, but you always want to add some dirt, because it should look a bit worn. Than this code might do the trick.

    My question is simply, if it could be optimized a bit?
    •  
      CommentAuthorbestdani
    • CommentTimeJan 5th 2017
     
    You could invert the alpha mask of the texture instead of doing it in the shader or just invert the lerp operands:

    tmp0.a = sub(1,Tex0.a);
    tmp2 = Lerp(tmp0.a, tmp0 , tex0);
    should be the same astmp2 = Lerp(Tex0.a, tex0 , tmp0);

    I have no idea how well things might be optimized automatically when the shader is compiled but you could probably get rid of some temporarily variables and set Result = Lerp(....) directly. and also replace tmp0 with tex0. When you use Result.rgb = ... you could maybe get rid of the result.a = 1 term (again I've no idea if these things have an peformance impact in the end).
    What finally would be left is just:
    result.rgb = lerp(tex0.a, tex0 , entity0);

    I didn't understand the second "question" since lerp and add are different operations.
    •  
      CommentAuthorFüchschen
    • CommentTimeJan 5th 2017
     
    ^
    thanks.
    more information via whisper.
    • CommentAuthorTOGO Fan
    • CommentTimeJan 7th 2017
     
    Is a Paternoster Elevator possible in NL2?

    https://www.youtube.com/watch?v=6o7K4ZW0pXc

    I would love to see one built in the game.
  7.  
    Is there a script or a way to make one to where it will do a controlled rotation of only 180 degrees?
    •  
      CommentAuthorFüchschen
    • CommentTimeJan 10th 2017
     
    @togo

    yes. Would work similar like this:
    https://www.youtube.com/watch?v=7hS7a35du1k

    Only up and downwards.
    The collision detection moves you always with the object, as soon as you walk on it.
    • CommentAuthorMr. E
    • CommentTimeJan 15th 2017 edited
     
    I've been using this attach to train script to attach the light to the train, and it works for train 1 but not train 2. Script is not mine.

    import com.nolimitscoaster.*;
    import nlvm.math3d.*;

    /* ***********************************************
    This is a generic object attachment script.

    Directions to use this script.
    1) Copy and paste attach_object.nlvm to the same directory as your .nl2sco file.
    2) Open the NL2SCO Editor and go to the Scripts tab.
    3) Select attach_object.nlvm from the Script Class dialog.
    4) Save the file and Refresh the scene object.

    View the in-game Help for creating .nl2sco files for your 3D models.

    It is unlikely that your object will be positioned exactly where you want it at first.
    You can modify the positional offset off the 3D model by adding or subtracting
    from xOffset, yOffset, zOffset below.
    **************************************************

    public class attach_object_car0 extends Script
    {
    // ====== CUSTOMIZABLE VARIABLES =======
    // Note: Decimal point "float" values must be followed by an 'f' (e.g. 0.5f, -9.205f). Whole values do not need the 'f'.
    private static final float xOffset = 0.01f; // left/right
    private static final float yOffset = -0.6f; //up/down
    private static final float zOffset = -0.2f; //back/forth
    private static final float range = 10; // The first train within this range of the scene object will receive the attachment. (range is in meters)
    private static final int carToAttach = 0 ; // Defines the car on the train that will receive the attachment. (0 = lead car or zero car)
    // ======================================

    private SceneObject sco; // Scenery object handle.
    private Train train; // Train handle.
    private Vector3f posOut = new Vector3f(0,0,0); // Will store the scenery object's position based on the car's position.
    private Vector3f pitchHeadBankOut = new Vector3f(0,0,0); // Will store the scenery object's orientation based on the car's orientation.
    private Matrix4x4f carMatrix = new Matrix4x4f(); // Will store the car's orientation.

    //**************************************************************************************
    // onInit is called when the scene object is loaded. Use this for initialization.
    // onInit should return true if initialization succeeds, else false.
    // If onInit returns false then the script will be disabled automatically and onNextFrame will never be called.
    //**************************************************************************************
    public bool onInit()
    {
    // ********************************************
    // Get the scene object handle.
    // ********************************************
    sco = sim.getSceneObjectForEntityId(getParentEntityId());
    if (sco == null)
    {
    System.err.println("attach_object.nlvm: This script must be assigned to a scene object.");
    return false;
    }

    // ********************************************
    // Determine if there is a track within range of the scenery object.
    // ********************************************
    TrackPos trackPos = sim.findNearestCoasterTrack(sco.getTranslation(), range);
    if (trackPos == null)
    {
    System.err.println("attach_object.nlvm: No track found within range of " + range + " meters.");
    return false;
    }

    // ********************************************
    // Determine if there is a train within range of the scenery object.
    // ********************************************
    Coaster coaster = trackPos.getCoaster();
    train = coaster.findNearestTrain(sco.getTranslation(), range);
    if (train == null)
    {
    System.err.println("attach_object.nlvm: No train found within range of " + range + " meters.");
    return false;
    }

    return true;
    }

    public void onNextFrame(float tick)
    {
    // ********************************************
    // Obtain the orientation matrix of the last car
    // ********************************************
    train.getCarMatrix(carToAttach, carMatrix);

    // ********************************************
    // Convert the matrix obtained from getCarMatrix()
    // to the Euler angle vector used in setRotation()
    // ********************************************
    Tools.matrixToPitchHeadBankPos(carMatrix, pitchHeadBankOut, posOut);

    // ***************
    // Calculate XYZ offset
    // ***************
    Matrix4x4f matrix = new Matrix4x4f();
    matrix.initTrans(xOffset, yOffset, zOffset);
    carMatrix.multRight(matrix);

    // ***************
    // Update the scene object's rotation and
    // position for this frame.
    // ***************
    Tools.matrixToPitchHeadBankPos(carMatrix, pitchHeadBankOut, posOut);
    sco.setRotation(pitchHeadBankOut);
    sco.setTranslation(posOut);
    }
    }


    This is the light with the problem

    This train has the light that works
    • CommentAuthorMrRC
    • CommentTimeJan 15th 2017 edited
     
    Play with these variables:

    "private static final float xOffset = 0.01f; // left/right
    private static final float yOffset = -0.6f; //up/down
    private static final float zOffset = -0.2f; //back/forth"

    And if u add this script to the object and for each train u have to place the light object in an certain range.
    •  
      CommentAuthorbestdani
    • CommentTimeJan 15th 2017 edited
     
    Edit
    It turned out that FrameListner.onNextFrame() calls indeed appear more often than Script.onNextFrame(...) calls which is an intentional behaviour.

    Original Post
    I currently came across a kind of unexpected problem, in which a SCO-Script (PanelCamera which extends from Script) initializes multiplie instances of a class (ButtonHandler that implements the FrameListener interface) during construction, these instances register themselves as frame listeners.

    The PanelCamera class queries the status of the ButtonHandler instances each frame (ButtonHandler.isTriggered()). On my system that worked as expected, the call order regarding to the Console is alternating:

    ButtonHandler.isTriggered() (called by PanelCamera.onNextFrame(float tick))
    ButtonHandler.onNextFrame()
    ButtonHandler.isTriggered() (called by PanelCamera.onNextFrame(float tick))
    ButtonHandler.onNextFrame()
    ButtonHandler.isTriggered() (called by PanelCamera.onNextFrame(float tick))
    ButtonHandler.onNextFrame()
    ...


    I've put that into a test package and that worked as expected on someone elses system, he moved the scripts into his project, where the call order turned out to be like:

    ButtonHandler.isTriggered() (called by PanelCamera.onNextFrame(float tick))
    ButtonHandler.onNextFrame()
    ButtonHandler.onNextFrame()

    ButtonHandler.isTriggered() (called by PanelCamera.onNextFrame(float tick))
    ButtonHandler.onNextFrame()
    ButtonHandler.onNextFrame()

    ButtonHandler.isTriggered() (called by PanelCamera.onNextFrame(float tick))
    ButtonHandler.onNextFrame()
    ButtonHandler.onNextFrame()
    ...

    Looks strange to me and resulted in unexpected behaviours (unfortunately I don't have access to his system to do some more investigations quickly).

    Therefore I've asked if he can send me his package to investigate if this is really a system dependent behaviour or something else caused by his setup.
    On my machine the call order (and amount!) was as desired again.

    Although I could resolve the problem by removing the automatic FrameListener registration of the ButtonHandler class (ButtonHandler.onNextFrame() is now explicitly called for each instance in PanelCamer.onNextFrame(tick)) which I consider not as nice as before (if it had worked as desired in any circumstances), I'm still wondering if this observation is something that is expected to happen or not. Had anyone tried to do the same with similar observattions already?
    •  
      CommentAuthorbestdani
    • CommentTimeJan 19th 2017
     
    Does anyone has an idea what bad habits of a (Sketchup) 3d model might cause that ExternalRideView.setCameraMatrix(SceneObjectElement.getAbsoluteMatrix()) will end up in a behaviour where the ride view camera is put into the correct position but with no applied rotation after some transformations of the SceneObjectElement?
    I could solve this behaviour to some extent by using Tools.MatrixToPitchHeadBankPosScale(...) and composing a view matrix myself from these values, I noticed that some tiny z scale might be applied to the matrix, but it could also be just some floating point imprecision I guess or another side effect of the real cause since scaling on a test model did also not resulted in such a behaviour.
  8.  
    So I'm working on a model to make a train more custom. How would I go about adding one of the NL nights to that model? Do I use two attachment scripts or can the Light object be imported into Sketchup and added to my model?
    • CommentAuthorMrRC
    • CommentTimeJan 19th 2017
     
    I use 1 script for each lightsource

    But u can import it into Sketchup and add it to your model and when adding the light source in your Tab : Light u can select the light source
    •  
      CommentAuthorrcth
    • CommentTimeJan 23rd 2017 edited
     
    I'm currently working on a huge project, which involves a lot of scripts and files. To use this correctly, I created a directory structure. Some of them are:
    /music
    /scripts

    One of the audio files is found in /music/station/safetyspiel.ogg

    The scripts are complex. I created a Master class which is included in the coaster. The master class is used to store all global data/variables and to link other classes with each other with the OOP solutions. One of the other classes is the blockscript.

    It seems like there is a problem when I try to create a package file.
    The used file 'C:\Users\Thimo\Documents\com.nolimitscoaster.nolimits2\Rock n Roller Coaster\scripts\Master.nlvm' contains a reference to another file using an absolute path (C:\Users\Thimo\Documents\com.nolimitscoaster.nolimits2\Rock n Roller Coaster\music\station\safetyspiel.ogg)

    The thing is, I've never used an absolute path in my code. Also, the code used for the onboard sound is almost the same and that seems to work.



    This is the line of code in question it's referencing.

    This is the code I used for the onboard audio referencing. The only difference is that here I reference to the audio in the same file, whereas in the other script I linked to another class which returned a StaticSound:



    Does anyone know why it doesn't work when I create a package? Running the ride from the .nl2park file works just fine.
    •  
      CommentAuthorYedrimas
    • CommentTimeJan 23rd 2017
     
    It's usually better to keep resources in the same directory or a sub directory.
    •  
      CommentAuthorbestdani
    • CommentTimeJan 23rd 2017 edited
     
    I think the package manager always replaces relative paths which point to a parent directory, this happened in different scenarios to me, too. The reason why it does recognize the first example but not in the second one is that it shouldn't be capable of recognizing the path in the second one at all (since it is not a constant String which should also give you warnings when the script is executed).

    In your cases you could add the music files as resources and use loadFromResourceId. I'm not entirely sure if using relative "backwards" paths in the NL2SCO would lead to the same error, if that's the case then the NL2SCO has to be in "../" relative from "script/", so you could use the classpath "script/", class "Master" and a resource for example "safety spiel" that points to "music/safetyspiel.ogg", but this is maybe just moving the problem to another spot (I would recommend to use resources anyway because of the warning that should pop up).

    Maybe this is even just a small bug, at least I agree that it is kind of unexpected behaviour, but although the folder hiearchies are somewhat limited because of this, it was no big deal for me for now - so I never considered reporting it as a possible bug. :D
    •  
      CommentAuthorrcth
    • CommentTimeJan 23rd 2017 edited
     
    It does give me warnings, but if I add these music files manually to the package, it works just fine. The warnings are annoying though, but it is needed because this way I have 2 scripts for all trains instead of 2 scripts each train (so 10 scripts).

    I added the safety spiel music file to the resources and it seems to work now :)
    •  
      CommentAuthorbestdani
    • CommentTimeJan 23rd 2017
     
    But adding all music files as resources and generating the resource Id name in the same manner as the file path would also work I guess (without having warnings and without having to remember to add the music files each time you create the package) ;-)
    •  
      CommentAuthorrcth
    • CommentTimeJan 23rd 2017
     
    I rewrote the scripts a little (thanks to Java's inheritance, saved me a lot of work) and use these resources now. It seems to work fine now.
  9.  
    Hi, I have Light so I want a fade Flickering light effect is there a script for this light?

    https://youtu.be/QZZdVEQXiK8 <--- Flickering Light
    •  
      CommentAuthorrcth
    • CommentTimeJan 24th 2017
     
    What would be the best way to slowly and smoothly move an object to a certain coordinate? I do it like this, but it isn't really smooth.

    float xLeft = this.defX - sco.getTranslation().x;
    float yLeft = this.defY - sco.getTranslation().y;
    float zLeft = this.defZ - sco.getTranslation().z;

    if (zLeft > 2) {
    sco.setTranslation(new Vector3f(defX, defY, sco.getTranslation().z + 0.1f));
    } else if (zLeft > 0.3f) {
    sco.setTranslation(new Vector3f(defX, defY, sco.getTranslation().z + 0.05f));
    } else if (zLeft > 0.05f) {
    sco.setTranslation(new Vector3f(defX, defY, sco.getTranslation().z + 0.01f));
    } else {
    sco.setTranslation(new Vector3f(defX, defY, defZ));
    this.isWaitingToMoveBack = false;
    }

    Does anyone have a better method that can move this object smoother?
    •  
      CommentAuthorbestdani
    • CommentTimeJan 24th 2017 edited
     

    // ...

    Vector3f v3StartPos = new Vector3f(3, 1, 4);
    Vector3f v3StopPos = new Vector3f(1, 5, 9);
    Vector3f v3CurrentPos = new Vector3f();

    float fLerpAmount; // 0.f -> v3StartPos, 1.f -> v3StopPos
    float fSpeedFactor = 0.3f; // higher -> faster

    // ...

    // for example in onNextFrame(float fTick):

    fLerpAmount += fSpeedFactor * fTick;
    v3CurrentPos.lerp((float)Tools.cubicRamp(fLerpAmount), v3StartPos, v3StopPos);
    sco.setTranslation(v3CurrentPos);

    You should do something when fLerpAmount reaches 1.0f (or 0.f) and clamp it to these values, for example stop the processing of the animation or reverse it as your code suggested.

    Maybe it's even better wrap around some some kind of general easing function or class around Tools.cubicRamp for example to replace it quickly by Tools.quitincRamp ore some custom easing functions quickly (you can find som NLVM implementations here by geforcefan, maybe also check this Easings Cheat Sheet).

    Since your code has hints that you want to do a continuous swinging between two positions it's maybe worth considering to use Math.sin(double a) or Math.cos(double a) as transition functions.
    •  
      CommentAuthorrcth
    • CommentTimeJan 25th 2017 edited
     
    Not exactly correct. It's a pushcar. It does swing between two positions, but from position A to position B it moves at the same speed of the train (attached). From B to A it has to move on its own.

    I'll take a look at the lerp code you provided.

    EDIT: It works smoothly now, thanks for the help.
  10.  
    Hi There,

    does anyone know how I can let a OffRide audio to go with triggers? Thanks
    •  
      CommentAuthorRCF
    • CommentTimeJan 28th 2017
     
    I have an animated video screen. How do I control it by a trigger and (optionally) add sound to it as well?
    • CommentAuthorMilBee
    • CommentTimeFeb 2nd 2017
     
    Does anyone happen to have a script for a coaster with two stations and the train goes back and forth? Something like the picture below.
  11.  
    I would like to have an on board sound trigger at the later of: the train passing a track trigger or the PRECEDING train passing a different track trigger (so when both conditions are satisfied)

    I think this is possible? Anyone care to help a scripting noob out?
    •  
      CommentAuthoriSatnav
    • CommentTimeFeb 4th 2017
     
    Any scripting wizards want to make me a block script so that the train will go onto the transfer, the transfer will slide across and then the train will launch? Whisper if you do please!

    https://gyazo.com/6d90ad06f7cdccb87777c58e39974608