New feature: Classes in scripting

All topics about ZGameEditor goes here.

Moderator: Moderators

User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

New feature: Classes in scripting

Post by VilleK »

Here is a build of ZGE with support for classes in scripting.

Basically it is using the syntax of C# and Java for declaring and using classes.

The main motivation for this feature:
- it will make it easier to port code from Java and other similar languages
- it makes it possible to write code in more object-oriented manner

Currently some limitations:
- there is no destructors. The reason for this is that the lifespan of a class instance is determined by the garbage collector and as such it may be destroyed after the code has finished running.

Attached is a ZGE build and also a demo project that use classes.

Please try it and see what you think about it. I'm sure there are bugs too so don't hesitate to report any crashes or weird syntax errors.

Here is an example of a class-declaration:

Code: Select all

class TPlayer {
  //This is the data of the class (a.k.a. "fields"). When they are declared private then only the code in the class can access them.
  private int score, lives;
  private int scoreRemainingToNextExtraLife = 10000;

  //This field is not private so outside code can access it  
  model theModel;
  
  TPlayer(int initialLives) {  //This is a constructor. It has the same name as the class and no returntype.
    lives = initialLives;
  }
  
  TPlayer() {  //There can be several constructors as long as they have different amount of arguments
    lives = 3;
  }

  //This is a function in the class (a.k.a. a "method").
  void giveScore(int amount) {
    score += amount;
    scoreRemainingToNextExtraLife -= amount;
    if(scoreRemainingToNextExtraLife<0) {
      lives ++;
      scoreRemainingToNextExtraLife += 10000;
    }
  }
  
  inline int getLives() { //Methods can be declared inline
    return lives;
  }
}
And then some code using this class:

Code: Select all

TPlayer p = new TPlayer(4);
p.theModel = null;  //non-private fields can be accessed directly
p.giveScore(100);  //call a method
trace(intToStr(p.getLives()));
Example of inheritance:

Code: Select all

class TBase {
  virtual void method1() {   //mark methods "virtual" if they should be overridden
  }
}

class TChild : TBase {  //specify ": TBase" to inherit from TBase class
  override void method1() {  //mark with "override" when overriding base class method
    //...
  }
}
Attachments
ZGameEditor_classes_beta6.zip
(4.47 MiB) Downloaded 273 times
ClassesDemo.zgeproj
(3.45 KiB) Downloaded 251 times
User avatar
Ats
Posts: 603
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: New feature: Classes in scripting

Post by Ats »

This is a neat update. I'll try that today.
I already have a few questions before starting, in this example:

Code: Select all

class TPlayer {
  private int lives;
  model playerModel;  
  TPlayer() {  } // Is it needed even though there is nothing inside?  
  inline int getLives() { return lives; } // what's the use of inline?
}

class TEnemy {
  private int lives; // Can we name a variable the same, or does it still have the same limitations?
  model enemyModel;  
  TEnemy () {  }  
  inline int getLives() { return lives; } // Same question for the function names
}

// And again, is it possible?
int lives = 0;
int getLives() { return lives(); }

TPlayer p = new TPlayer();
TEnemy e = new TEnemy();

trace(intToStr(p.getLives()));
trace(intToStr(e.getLives()));
trace(intToStr(getLives()));
User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: New feature: Classes in scripting

Post by VilleK »

Ats wrote: Fri May 28, 2021 8:27 am TPlayer() { } // Is it needed even though there is nothing inside?
Not needed, just an example :)
Ats wrote: Fri May 28, 2021 8:27 am inline int getLives() { return lives; } // what's the use of inline?
Inline is a performance feature. It removes the overhead of a function call. See https://en.wikipedia.org/wiki/Inline_expansion
Ats wrote: Fri May 28, 2021 8:27 am class TEnemy {
private int lives; // Can we name a variable the same, or does it still have the same limitations?
inline int getLives() { return lives; } // Same question for the function names
Different classes can have variables with same name. And also methods. Let me know if it doesn't work.
Ats wrote: Fri May 28, 2021 8:27 am // And again, is it possible?
int lives = 0;
int getLives() { return lives(); }
Global functions and variables should be possible to have the same name too.
User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: New feature: Classes in scripting

Post by VilleK »

Updated build in first post with some bugfixes.
User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: New feature: Classes in scripting

Post by VilleK »

Another useful syntax enhancement in this build is the ability to initialize an array directly on declaration:

Code: Select all

byte[] data = {1,2,3,4};  // declare and initialize an array with 4 items and the values 1,2,3,4
Only works with one-dimensional arrays so far.
User avatar
Ats
Posts: 603
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: New feature: Classes in scripting

Post by Ats »

Wow. This is going to be really helpful for my project.
Sorry I couldn't test it this weekend. Tomorrow I'll have some time for that :wink:
User avatar
Ats
Posts: 603
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: New feature: Classes in scripting

Post by Ats »

So far so good with simple projects. But this version of ZGE doesn't seem to load external dll and just displays "ZgeBullet" at start. So I can't test it with Omeganaut.
User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: New feature: Classes in scripting

Post by VilleK »

Ats wrote: Tue Jun 01, 2021 9:54 am But this version of ZGE doesn't seem to load external dll and just displays "ZgeBullet" at start.
This is most likely because this is a 64-bit build. Do you have a 64-bit ZgeBullet DLL to try with?

I would prefer to have the 64-bit version as the primary ZGE build from now on if possible.
User avatar
Ats
Posts: 603
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: New feature: Classes in scripting

Post by Ats »

All right. It's working perfectly then :lol:
User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: New feature: Classes in scripting

Post by VilleK »

Another useful feature: ZGE now shows a callstack of the script if an script error occurs.

Consider a project with a function f() that calls another function g() that calls h() which leads to an runtime error. Previously you would only get an error in the log window without any clue where the error was.

Now you will get a callstack like shown in the screenshot below. The first line is the name of the function where the error happened "h". Then the lines afterwards are the calls leading up to the error, including the initial ZExpression. I've attached a sample project with this example.

Updated zip in first post with new build.
zge_callstack.png
zge_callstack.png (6.03 KiB) Viewed 11957 times
Attachments
callstack_test.zgeproj
(412 Bytes) Downloaded 243 times
User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: New feature: Classes in scripting

Post by VilleK »

Here is a ZGE port of Chuckie Egg, based on this: https://github.com/pbrook/Chuckie-Egg

The "struct" definitions in the C code could be converted to classes in ZGE.

Chuckie Egg is a classic 8-bit game: https://en.wikipedia.org/wiki/Chuckie_Egg
It is a bit like Donkey Kong with ducks :)

Use QAOP and Space to play using keyboard or use gamepad.
Attachments
chuckieegg.png
chuckieegg.png (24.3 KiB) Viewed 11861 times
ChuckieEgg.zgeproj
(48.31 KiB) Downloaded 257 times
User avatar
Ats
Posts: 603
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: New feature: Classes in scripting

Post by Ats »

Nice old game. Very tricky to climb and get of the ladders :lol:
What is that for?

Code: Select all

if(ANDROID) {
  if(App.GLBase==0)
    this.ModuleName="libGLESv1_CM.so";
  else
    this.ModuleName="libGLESv2.so";
}
And you should add :

Code: Select all

else
{
  this.ModuleName = "opengl32";
}
because preview replaces the ZExternalLibrary.ModuleName, which is a bit weird. So if you want to play it on computer, you need to replace it again to opengl32.

EDIT: in fact, it's even weirder, in preview mode, ZExternalLibrary.ModuleName is always replaced by "libGLESv2.so"...?
The preview mode on Windows is retuning true for if (ANDROID) :?



Regarding the declaration of arrays, how would you declare a global array using your new method?

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" FileVersion="2">
  <OnLoaded>
    <ZLibrary Source="string[] data = {&quot;abricot&quot;,&quot;banane&quot;,&quot;cerise&quot;};"/>
    <ZExpression Expression="//string[] data = {&quot;abricot&quot;,&quot;banane&quot;,&quot;cerise&quot;};"/>
  </OnLoaded>
  <OnUpdate>
    <ZExpression Expression="trace(intToStr(data.SizeDim1));"/>
  </OnUpdate>
</ZApplication>
User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: New feature: Classes in scripting

Post by VilleK »

The gl-component is from using right click add from library option in project tree. I guess it is not up to date. But if Android is true how can it work at all?

I think there was something not working with global arrays yet, so atm you have to declare it in a class and use that:

Code: Select all

class TMyGlobals {
  string[] data = ...
}

TMyGlobals globals = new TMyGlobals();
User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: New feature: Classes in scripting

Post by VilleK »

Inheritance in classes is now implemented. Updated beta in first post and the classesdemo-project now use inheritance.
User avatar
VilleK
Site Admin
Posts: 2274
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: New feature: Classes in scripting

Post by VilleK »

Updated beta in first post.

As a test project for the class inheritance feature I ported a simple NES emulator from Java to ZGE.

It is a very basic emulator that only seem to support 24kb NES files. And ZGE scripting struggles a bit to keep up a stable frame rate. But it works :). The main purpose here was not to make a fully featured emulator but just to test virtual functions.

CPU emulation is implemented with a virtual base class that is then inherited for each specific instruction like this:

Code: Select all

class TInstruction {
  virtual void ope(int i) { }
  virtual void opeAccumulator() {  }
}

class TANDInstruction : TInstruction {
  override void ope(int i) {
    a = a&mem_read(i);
    ZeroFlag = (a==0);
    NegativeFlag = bit(a,7) == 1;
  }
}

// shift left
class TASLInstruction : TInstruction {
  override void ope(int i) {
    int temp = mem_read(i)*2;
    mem_write(i, temp);
    CarryFlag = bit(temp,8) == 1;
    ZeroFlag = (temp&0xff) == 0;
    NegativeFlag = bit(temp,7) == 1;
  }
  override void opeAccumulator(){
    int temp = a*2;
    a = temp&0xff;
    CarryFlag = bit(temp,8) == 1;
    ZeroFlag = a == 0;
    NegativeFlag = bit(a, 7) == 1;
  }
}
I'm pleased to see this working and hope even more advanced projects can be ported to ZGE in the future.
Attachments
NesEmu.zgeproj
(56.23 KiB) Downloaded 226 times
zge_nes.png
zge_nes.png (271.26 KiB) Viewed 11593 times
Post Reply