Page 1 of 2 12 LastLast
Results 1 to 10 of 19

Thread: Scripting

  1. #1

    Scripting

    Hi Jarrod,

    I've started playing around with the latest version of PyroGine(v0.4.2) and despite the lack of documentation I'm liking it

    I was wondering if you could give me a small example on how to use the scripting system. I've seen how you can compile and run the full AstroBlaster demo but that's not quite what I want. I would like to know how I can expose specific entities to a script so the script can manipulate the entities?

    For instance a script can define the logic for an enemy, so for each TEnemy inheriting from TPGEntity, I'll call the EnemyLogic script during each update.
    Imagine I've written something clever here inspiring you to make something awesome. If that happens give me credits

  2. #2

    Re: Scripting

    @pstudio

    Coolness, thanks. Sure, that can be done with PGE. Wait for my reply and I will post a small demo that will show how this is done.
    Jarrod Davis
    Technical Director @ Piradyne Games

  3. #3

    Re: Scripting

    Thanks

    The build-in scripting system is one of the thing about Pyro that makes it stand out compared to other solutions IMO.
    Imagine I've written something clever here inspiring you to make something awesome. If that happens give me credits

  4. #4

    Re: Scripting

    Ok, here is an example of controlling the ship in script from the host side.

    host side:
    [code=delphi]program pstudio_scripting;

    {$APPTYPE CONSOLE}

    uses
    SysUtils,
    PGSystem,
    PGGraphics,
    PGActor,
    PGScript,
    PGApplication;

    type
    { --- TScript --------------------------------------------------------------- }
    TScript = class(TPGScript)
    protected
    FLastModual: string;
    public
    constructor Create; override;
    destructor Destroy; override;
    procedure OnCompilerProgress; override;
    end;

    { --- TShip ----------------------------------------------------------------- }
    TShip = class(TPGEntity)
    public
    constructor Create; override;
    destructor Destroy; override;
    function NextFrame: Boolean; override;
    procedure RotateRel(aAngle: Single); override;
    procedure Thrust(aSpeed: Single); override;
    end;

    { TShipUpdate }
    TShipUpdate = procedure(aShip: TShip; aElapsedTime: Single);

    { --- TScript --------------------------------------------------------------- }
    constructor TScript.Create;
    begin
    inherited;
    FLastModual := '';
    end;

    destructor TScript.Destroy;
    begin
    inherited;
    end;

    procedure TScript.OnCompilerProgress;
    begin
    if FLastModual <> Self.GetCurrModuleName then
    begin
    FLastModual := Self.GetCurrModuleName;
    WriteLn('Compiling ',FLastModual,'...');
    end;
    end;


    { --- TShip ----------------------------------------------------------------- }
    constructor TShip.Create;
    begin
    inherited;
    end;

    destructor TShip.Destroy;
    begin
    inherited;
    end;

    function TShip.NextFrame: Boolean;
    begin
    inherited;
    end;

    procedure TShip.RotateRel(aAngle: Single);
    begin
    inherited;
    end;

    procedure TShip.Thrust(aSpeed: Single);
    begin
    inherited;
    end;

    var
    Sprite: TPGSprite;
    Page : Integer;
    Group : Integer;
    Ship : TShip;
    Script: TScript;
    Ship_Update: TShipUpdate;

    { --- Demo ------------------------------------------------------------------ }
    function Demo_Init: Boolean;
    var
    i: Integer;
    s: string;
    begin
    Result := False;

    // init display device
    PG.DisplayDevice.Open('pstudio - Scripting', dm800x600, True, True);

    // init render device
    PG.RenderDevice.SetMode(0, seDiscard);

    // init sprite object
    Sprite := TPGSprite.Create;

    // load ship texture
    Page := Sprite.LoadPageFromFile('ship.png', PG_ColorKey);

    // add ship group
    Group := Sprite.AddGroup;

    // add images to ship group
    Sprite.AddImageFromGrid(Page, Group, 0, 1, 64, 64);
    Sprite.AddImageFromGrid(Page, Group, 1, 1, 64, 64);
    Sprite.AddImageFromGrid(Page, Group, 2, 1, 64, 64);

    // init ship entity
    Ship := TShip.Create;
    Ship.Init(Sprite, Group);
    Ship.FrameFPS := 14;
    Ship.SetPosAbsXY(400, 300);

    // init script manager
    Script := TScript.Create;

    // register TShip class type
    i := Script.RegisterClassType(0, TShip);

    // register TShip methods
    Script.RegisterHeader(i, 'constructor Create; override;', @TShip.Create);
    Script.RegisterHeader(i, 'destructor Destroy; override;', @TShip.Destroy);
    Script.RegisterHeader(i, 'function NextFrame: Boolean; override;', @TShip.NextFrame);
    Script.RegisterHeader(i, 'procedure RotateRel(aAngle: Single); override;', @TShip.RotateRel);
    Script.RegisterHeader(i, 'procedure Thrust(aSpeed: Single); override;', @TShip.Thrust);

    // add a new pascal module
    Script.AddModule('ship_logic', lsPascal);

    // add source into pascal module
    Script.AddCodeFromFile('ship_logic', 'ship_logic.pas');

    // compile the script
    if Script.Compile then
    begin
    // get the address of update routine
    Ship_Update := Script.GetAddress('Ship_Update');

    // check if valied
    if not Assigned(Ship_Update) then
    begin
    PG.ShowMessage('debug', 'Failed to get routine address', &#91;]);
    Exit;
    end;
    end
    else
    begin
    // display errors
    for i := 0 to Script.GetErrorCount - 1 do
    begin
    s := Format('%s(%d:%d):%s', [Script.GetErrorModuleName(i),
    Script.GetErrorLineNumber(i) + 1, Script.GetErrorLinePos(i) + 1,
    Script.GetErrorMessage(i)]);
    WriteLn(s);
    end;
    PG.ConPause('Press ENTER to continue...');
    Exit;
    end;

    Result := True;
    end;

    procedure Demo_Done;
    begin
    // destroy script
    PG_FreeAndNil(Script);

    // destroy sprite
    PG_FreeAndNil(Sprite);

    // restore desktop mode
    PG.RenderDevice.RestoreMode;

    // close display device
    PG.DisplayDevice.Close;
    end;

    procedure Demo_Update(aElapedTime: Single);
    begin
    // update ship via script
    Ship_Update(Ship, aElapedTime);
    end;

    procedure Demo_Render;
    begin
    // render ship
    Ship.Render(0, 0);
    end;

    procedure Demo_Run;
    begin
    // game loop
    while not PG.Terminated do
    begin
    // process windows messages
    PG.ProcessMessages;

    // check if the render device is ready, loop if not
    if not PG.RenderDevice.Ready then
    begin
    continue;
    end;

    // update timing
    PG.Timer.Update;

    // update demo
    Demo_Update(PG.Timer.ElapsedTime);

    // clear frame buffer
    PG.RenderDevice.ClearFrame(cfDefault, PG_SkyBlue);

    // start frame
    if PG.RenderDevice.StartFrame then
    begin
    // render demo
    Demo_Render;

    // end frame
    PG.RenderDevice.EndFrame;
    end;

    // show frame buffer
    PG.RenderDevice.ShowFrame;
    end;
    end;

    { --- Main ------------------------------------------------------------------ }
    var
    ok: Boolean;
    begin
    // init demo
    ok := Demo_Init;
    try

    // if all ok run demo
    if ok then
    begin
    Demo_Run;
    end;
    finally

    // shut down demo
    Demo_Done;
    end;
    end.[/code]

    script side:
    [code=pascal]
    // update native TShip from compiled script
    procedure Ship_Update(aShip: TShip; aElapedTime: Single);
    begin
    // update next frame
    aShip.NextFrame;

    // rotate to new angle
    aShip.RotateRel(3.0*aElapedTime);

    // thrust in the direction of rotate
    aShip.Thrust(7.0*aElapedTime);
    end;

    begin
    end.[/code]

    You can download the Delphi project here.

    Comments:[*]Even though TPGEntity is already registered by the scripting system, because TObject is crossing the DLL boundary you will still need to registered all methods and routines that you want "seen" by the scripting system from the host side.[*]Once the script is compiled, you can use GetAddress to get the address of a script object (variable, routine, method)[*]If you wanted to access a class on the script side you would simply call CreateObject, GetAddress to get it's address, and finally call DestroyObject to destroy the class.[*]Note it really does not matter which direction you take because the compiled script is x86 native code. On average it will be about 3 times slower than optimized Delphi code.[*]All the examples from the pascal folder are standalone compile versions which shows just how fast the scripting system really is.[*]Scripts can be compiled and save out to a DLM (Dynamic Loadable Module). You can then load this in at run-time to access your routines and classes.[*]The whole SDK is already registered so from script you have access to PGE and can do almost anything in script, including loading in other DLMs and having the running script access that.
    Jarrod Davis
    Technical Director @ Piradyne Games

  5. #5

    Re: Scripting

    Wow Great Thanks

    And it is impressive that it all compiles to native x86 code. PyroGine seems to be an impressive engine.

    I suppose StellarDefense is ment to show just how awesome PyroGine is?
    Imagine I've written something clever here inspiring you to make something awesome. If that happens give me credits

  6. #6

    Re: Scripting

    No worries. I'm here to help. In fact during the weekends I will try to be on IM if anyone needs me.

    You can find me via IM on one of these:

    Windows IM GoogleTalk Yahoo IM
    ------------------------------------------------------
    pyroginedev [ at ] hotmail.com | gmail.com | yahoo.com

    Astra (Trillian)
    ------------------------------------------------------
    pyrogine [ at ] pyrogine.com


    Yea, I'm currently working on SD. I made PGE to make games. My vision was to get the engine to a point where I can do maybe 1-2 games per year and about once a year or so then do a major overhaul on the engine. The next major version will focus on cross platform support. SD will show case the great features of PGE, yes.

    On one thing... I need to add the PG DLL in the distro because I had to fix a few bugs making this demo. This is why it took a bit to finish. Wait for a few min and then re download from the same link. Sorry about that.
    Jarrod Davis
    Technical Director @ Piradyne Games

  7. #7

    Re: Scripting

    Ok, I've re uploaded a new demo that include the PyroGine.dll. When working on this for you, I discovered and fixed a few errors relating to scripting. So, thanks for the request.

    To compile and run this demo and anything relating to scripting you need to include this version or higher of the DLL. The next release will have this fix included.

    Jarrod Davis
    Technical Director @ Piradyne Games

  8. #8

    Re: Scripting

    Thanks again.
    I noticed it wasn't working with the old dll but all is working fine now.
    EDIT: Apparently I can't compile the project myself. I get the following error:
    [Pascal Error] pstudio_scripting.dpr(72): E2008 Incompatible types
    at

    [pascal]function TShip.NextFrame: Boolean;
    begin
    inherited; // Here
    end;[/pascal]


    I do have one question though. What exactly is the Integer argument 'aLevelId' in TPGScript.RegisterClassType and TPGScript.RegisterHeader and what does the return value mean?
    Imagine I've written something clever here inspiring you to make something awesome. If that happens give me credits

  9. #9

    Re: Scripting

    Hmm....

    Try this:
    [code=delphi]function TShip.NextFrame: Boolean;
    begin
    Result := inherited NextFrame;
    end;
    [/code]

    aLevel is the current level for the object your registering. For example, if you are registering a name space, then for all the objects that should go in this name space you pass in that value. Such as this:

    [code=delphi]// register name and return an id
    n := Script.RegisterNamespace('MyStuff');

    // register TMyClassStuff in the 'MyStuff' name space
    c := Script.RegisterClassType(n, TMyClassStuff);

    // the return value of c can be used to finish register methods and type related to the class
    [/code]

    Oh, what version of Delphi are you using? If the above does not work I will zip up the distro. I may have made some changes to the interfaces the last few days.


    Jarrod Davis
    Technical Director @ Piradyne Games

  10. #10

    Re: Scripting

    Here is the current PGE v0.4.3 build, try it.
    Jarrod Davis
    Technical Director @ Piradyne Games

Page 1 of 2 12 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •