Smart Mobile Studio
  • News
  • Forums
  • Download
  • Store
  • Showcases
    • Featured demos
    • The Smart Contest 2013, Round 1 – Graphics
  • Documentation
    • Get the book
    • System requirements
    • Prerequisites
    • Getting started
      • Introduction
      • Application architecture
      • The application object
      • Forms and navigation
      • Message dialogs
      • Themes and styles
    • Project types
      • Visual project
      • Game project
      • Console project
    • Layout manager
    • Networking
      • TW3HttpRequest
      • TW3JSONP
      • Loading files
  • About

Tag Archives: code

SPNG: Be informed when values change

Posted on 08.04.2017 by Jon Lennart Posted in Developers log, News, News and articles 2 Comments

There are many new and powerful features in the upcoming release of Smart Mobile Studio (also refered to as Smart Pascal, Next Generation: SPNG in short): One of the most powerful is the ability to be notified when a value or object changes with a single line of code.

So far TVariant has just been a helper class for dealing with typical tasks. Well, perhaps not just typical because under Smart Pascal, variants can map directly to a javascript object (of any type) and allows you direct access to its prototype. The Handle property that all visual controls have is an example of this. The type TControlHandle is actually a reference to the visual element inside the DOM (document object mode). So by accessing that directly in your code, you can change styles, attributes and properties of that element. You are not bounds to only use our pre-fabricated solutions.

In the next update TVariant have a lot of new members. Two that stands out as important: watch() and unwatch().

As their name imply they will warch something for you. In this case you wil be notified whenever a single property, a whole object or indeed – a property deep within an object is altered. It may sound trivial but it’s actually one of those features that lays the foundation for responsive, data-aware controls.

But you can use it for many other things as well. For example you can now attach an event directly to a string. And whenever that string changes (either by your code, the user, or some other script) you can act on it directly. That is pretty cool and very helpful!

  // create an empty javascript object
  var MyValue: Variant := TVariant.CreateObject();

  // Set a default value
  MyValue.NewProperty := 12; // add a property and set a value

  // We want to know when the object changes
  TVariant.Watch(MyValue, "NewProperty", procedure ()
    begin
      showmessage("You changed the value!");
    end);

In this snippet we setup a javascript object and place a named-property inside that object. We then listen for changes to that property (by name even). So if you change that value further down in the code, or by calling some procedure elsewhere – the event will fire and show the message dialog.

This is of-cource just a tiny fragment of the new code that has been added, not to mention the changes and fixes. Some of these features are presently in alpha stage and is being tested. We will post more and more news in the days and weeks ahead – and we are sure you will be pleased with some the fantastic new things you can now code!

Here is an example of the new desktop and windowing applications you can write (picture below): The smart desktop!

The Smart desktop

We decided to update the uartex Media Desktop, an example initially made for touch based embedded environments – and turned it into a fully functional desktop environment!

Both the desktop itself, the filesystem, the IO drivers and windowing toolkit is written in Smart Pascal. You can create kiosk software designed to run on embedded devices, advanced applications designed to run on your intranet – or full cloud systems. So it can run a Smart application inside each Window if you like. But you have full control over windows, file access, directly listings, menu items and can sculpt both the desktop and applications to suit your needs.

The desktop can be coupled with a node.js backend that handles multi-user login and file access. It gives your users access to designated home-folders (again under your control). So each user can have their own work files just like a thin client, and each user can run different applications from a fully working desktop environment.

Below you are seeing Quake II compiled from C/C++ to LLVM bitcode. This is in turn compiled to JavaScript via asm.js. This means the browser will compile the javascript into machine code after loading. So Quake II runs at native speed, all JavaScript, inside our desktop window.

Create windowed applications with Smart Desktop

Create windowed applications with Smart Desktop

You will also be happy to head that x86 Linux and ARM kiosk distros have been created. So once happy with your desktop you can in fact boot straight into it in fullscreen. No Linux desktop or shell — just your desktop running. Both Firefox and Chrome can be used as presenter.

Have a great easter!

announcement code demo HTML5 javascript Object Pascal OP4JS release Smart Mobile Studio Upcoming features

Events as objects

Posted on 18.01.2016 by Jon Lennart Posted in Developers log 5 Comments

Events are fun right? Well, only in part to be honest. For example, what do you do if you want to catch the same event but at different places?

This is where JavaScript’s addEventListener() comes into play. In short it allows you to add as many event-handlers to the same event as your heart desires. But raw unadulterated JavaScript is a bit of a mess, so I decided to wrap this up in clear cut objects. Oh, and I added a “fixed” event for when you want to have objects for standard events as well.

So now whenever you want to hook an event without ruining your published event-handlers (for instance in TW3CustomControl) you can just use one of these 🙂

Enjoy!

unit eventobjs;

interface

uses 
  w3c.dom,
  SmartCL.Components,
  SmartCL.System;

type


  TEventObjTriggeredEvent = procedure (sender:TObject;EventObj:JEvent);

  TEventObj = class(TObject)
  private
    FOwner:     TW3TagObj;
    FAttached:  Boolean;
    FEventName: String;
  protected
    procedure   HandleEvent(eobj:variant);virtual;
  public
    Property    Attached:Boolean read FAttached;
    procedure   Attach(EventName:String);
    procedure   Detach;
    constructor Create(AOwner:TW3TagObj);virtual;
    destructor  Destroy;Override;
  public
    Property    EventName:String read FEventName;
    Property    Owner:TW3TagObj read FOwner;
    Property    OnEvent: TEventObjTriggeredEvent;
  end;

  TFixedEventObj = class(TObject)
  protected
    FAttached:  Boolean;
    FOwner:     TW3TagObj;
    procedure   HandleEvent(eobj:variant);virtual;
  protected
    function    DoGetEventName:String;virtual;abstract;
  public
    Property    Attached:Boolean read FAttached;
    procedure   Attach;
    procedure   Detach;
    constructor Create(AOwner:TW3TagObj);virtual;
    destructor  Destroy;override;
  public
    Property    Owner:TW3TagObj read FOwner;
    Property    OnEvent: TEventObjTriggeredEvent;
  end;

  TElementRemovedEvent = class(TFixedEventObj)
  protected
    function  DoGetEventName:String;override;
  end;

  TElementAddedEvent = class(TFixedEventObj)
  protected
    function  DoGetEventName:String;override;
  end;

implementation


//#############################################################################
// TElementAddedEvent
//#############################################################################

function TElementAddedEvent.DoGetEventName:String;
begin
  result := "DOMNodeInserted";
end;

//#############################################################################
// TElementRemovedEvent
//#############################################################################

function TElementRemovedEvent.DoGetEventName:String;
begin
  result := "DOMNodeRemoved";
end;

//#############################################################################
// TFixedEventObj
//#############################################################################

constructor TFixedEventObj.Create(AOwner:TW3TagObj);
begin
  inherited Create;
  FOwner:=AOwner;
  Attach;
end;

destructor TFixedEventObj.Destroy;
begin
  Detach;
  inherited;
end;

procedure TFixedEventObj.Attach;
begin
  if FAttached then
  Detach;
  FOwner.Handle.addEventListener(DoGetEventName,@HandleEvent,true);
  FAttached := true;
end;

procedure TFixedEventObj.Detach;
begin
  if FAttached then
  begin
    FOwner.Handle.removeEventListener(DoGetEventName,@HandleEvent,true);
    FAttached := false;
  end;
end;

procedure TFixedEventObj.HandleEvent(eObj:variant);
begin
  if assigned(OnEvent) then
  OnEvent(self, JEvent(eObj));
end;

//#############################################################################
// TEventObj
//#############################################################################

constructor TEventObj.Create(AOwner:TW3TagObj);
begin
  inherited Create;
  FOwner := AOwner;
end;

destructor TEventObj.Destroy;
begin
  if FAttached then
  Detach;
  inherited;
end;

procedure TEventObj.HandleEvent(eobj:variant);
begin
  if assigned(OnEvent) then
  OnEvent(self,JEvent(eObj));
end;

procedure TEventObj.Attach(EventName:String);
begin
  if FAttached then
  Detach;

  FEventName := EventName;
  try
    FOwner.handle.addEventListener(FEventName,@HandleEvent,true);
  except
    FEventname:= '';
    FAttached:=false;
    exit;
  end;
  FAttached:=true;
end;

procedure TEventObj.Detach;
begin
  if FAttached then
  begin
    try
      FOwner.handle.removeEventListener(FEventName,@HandleEvent,true);
    finally
      FEventName := '';
      FAttached := false;
    end;
  end;
end;

end.
code events HTML5 javascript Object Pascal OP4JS Pascal Smart Mobile Studio w3C

Structures, dealing with name pairs

Posted on 26.09.2015 by Jon Lennart Posted in Developers log

When talking to your REST server or nodeJS service, it can sometimes be overkill to ship a huge and complex wad of JSON or XML over the wire. I noticed that WebSocket transferes can sometimes get a tiny delay if the server is dealing with high payloads. Although we are talking milliseconds here, it’s always good to refactor and make things as small as possible.

The solution I came up with is essentially a dynamically created “record”. Where you would normally write:

type
  TMyData = record
    field1: String;
    field2: TDateTime;
    field3: Integer;
  end;

TW3Structure allows you to do this programatically, both for binary and JSON. Which can be handy when playing around with your own protocols. So with TW3Structure you can do stuff like:

var Structure := TW3JsonStructure.Create(null);
Structure.WriteString('field1','some value');
Structure.WriteDateTime('field1',Now);
Structure.WriteInt('field2',1200);

var JSONData:String;
Structure.SaveToJSON(JSONData);

WebSocket.Send(JSONData);

I also added support for TStream which does the exact same thing, but in true binary form. Perfect for storing simple data in the browser cache or your mobile device’s sandbox.

unit system.namepair;

interface

uses
  System.types,
  System.streams,
  SmartCL.System;

type

  EW3Structure = class(EW3Exception);
  TW3Structure = Class(TObject)
  public
    procedure   WriteString(name:string;value:String;
                const encode:Boolean);overload;
    procedure   WriteInt(name:string;Value:Integer);overload;
    procedure   WriteBool(name:string;value:Boolean);overload;
    procedure   WriteFloat(name:String;value:Float);overload;
    procedure   WriteDateTime(name:String;value:TDateTime);overload;

    procedure   Write(name:String;value:variant);overload;virtual;abstract;

    procedure   Clear;virtual;abstract;

    procedure   SaveToJSON(var Data:String);virtual;abstract;
    procedure   LoadFromJSON(Value:String);virtual;abstract;

    procedure   SaveToStream(Stream:TStream);virtual;abstract;
    procedure   LoadFromStream(Stream:TStream);virtual;abstract;
  end;

  TW3JsonStructure = Class(TW3Structure)
  private
    FBuffer:  Variant;
  public
    procedure   Clear;override;
    procedure   SaveToJson(var Data:String);override;
    procedure   LoadFromJson(Value:String);override;
    procedure   SaveToStream(Stream:TStream);override;
    procedure   LoadFromStream(Stream:TStream);override;

    procedure   Write(name:String;value:variant);overload;override;
    Constructor Create(const Data:Variant);virtual;
  end;


  TW3BinProxyItem = Record
    daName:   String;
    daValue:  Variant;
  end;

  TW3BinaryStructure = Class(TW3Structure)
  private
    FData:      Array of TW3BinProxyItem;
    function    IndexOfName(name:String):Integer;
  protected
    procedure   Clear;override;
    procedure   SaveToJson(var Data:String);override;
    procedure   LoadFromJson(Value:String);override;
    procedure   SaveToStream(Stream:TStream);override;
    procedure   LoadFromStream(Stream:TStream);override;
    procedure   Write(name:String;value:variant);overload;override;
  end;


implementation

resourcestring

CNT_ERR_STRUCTURE_FUNCTION  =
'Stream storage failed, structure contains function reference error';

CNT_ERR_STRUCTURE_SYMBOL  =
'Stream storage failed, structure contains symbol reference error';

CNT_ERR_STRUCTURE_UNKNOWN =
'Stream storage failed, structure contains uknown data-type error';

CNT_ERR_STRUCTURE_FAILEDREAD =
'Failed to read structure, invalid datatype error';

CNT_ERR_STRUCTURE_INVALIDSIGN =
'Failed to read structure, invalid data signature error';

//############################################################################
// TW3BinaryStructure
//###########################################################################

const
CNT_STRUCT_SIGNATURE  = $CCCCFF00;

function TW3BinaryStructure.IndexOfName(name:String):Integer;
var
  x:  Integer;
begin
  result:=-1;
  if FData.Count>0 then
  for x:=FData.low to FData.high do
  begin
    if Sametext(Fdata[x].daName,Name) then
    begin
      result:=x;
      break;
    end;
  end;
end;

procedure TW3BinaryStructure.Write(name:String;value:variant);
var
  mIndex: Integer;
  mItem:  TW3BinProxyItem;
Begin
  mIndex:=IndexOfName(name);
  if mIndex<0 then
  begin
    mItem.daName:=name;
    mItem.daValue:=Value;
    FData.add(mItem);
  end else
  FData[mIndex].daValue:=Value;
end;

procedure TW3BinaryStructure.Clear;
Begin
  FData.Clear;
end;

procedure TW3BinaryStructure.SaveToJson(var Data:String);
Begin
  asm
    @Data = json.stringify( (@self.FData) );
  end;
end;

procedure TW3BinaryStructure.LoadFromJson(Value:String);
Begin
  asm
    (@self.FData) = json.parse(@Value);
  end;
end;

procedure TW3BinaryStructure.SaveToStream(Stream:TStream);
var
  x:  Integer;
  mWriter:  TWriter;
Begin
  mWriter:=TWriter.Create(Stream);
  try
    mWriter.WriteInteger(CNT_STRUCT_SIGNATURE);
    mWriter.WriteInteger(FData.Count);
    if FData.Count>0 then
    begin
      for x:=0 to FData.Count-1 do
      begin
        /* Write the name */
        mWriter.WriteString(FData[x].daName);

        /* Write the datatype */
        mWriter.WriteInteger(ord(FData[x].daValue.datatype));

        /* Write the value */
        case FData[x].daValue.datatype of
        vdBoolean:
          begin
            mWriter.WriteBoolean(FData[x].daValue);
          end;
        vdInteger:
          begin
            mWriter.WriteInteger(FData[x].daValue);
          end;
        vdFloat:
          begin
            mWriter.WriteDouble(FData[x].daValue);
          end;
        vdString:
          begin
            mWriter.WriteString(FData[x].daValue);
          end;
        vdFunction:
          begin
            Raise EW3Structure.Create(CNT_ERR_STRUCTURE_FUNCTION);
          end;
        vdSymbol:
          begin
            Raise EW3Structure.Create(CNT_ERR_STRUCTURE_SYMBOL);
          end;
        vdUnknown:
          begin
            Raise EW3Structure.Create(CNT_ERR_STRUCTURE_UNKNOWN);
          end;
        end;
      end;
    end;
  finally
    mWriter.free;
  end;
end;

procedure TW3BinaryStructure.LoadFromStream(Stream:TStream);
var
  mCount:   Integer;
  mReader:  TReader;
  mKind:    Integer;
  mRec:     TW3BinProxyItem;
Begin
  Clear;
  mReader:=TReader.Create(Stream);
  try
    if mReader.ReadInteger = CNT_STRUCT_SIGNATURE then
    begin
      mCount:=mReader.ReadInteger;
      while mCount>0 do
      begin
        mRec.daName:=mReader.ReadString;
        mKind:=mReader.ReadInteger;
        case TW3VariantDataType(mKind) of
        vdBoolean:  mRec.daValue:=mReader.ReadBoolean;
        vdInteger:  mRec.daValue:=mReader.ReadInteger;
        vdFloat:    mRec.daValue:=mReader.ReadDouble;
        vdString:   mRec.daValue:=mReader.ReadString;
        else
          Raise EW3Structure.Create(CNT_ERR_STRUCTURE_FAILEDREAD);
        end;

        FData.add(mRec);
        mRec.daName:="";
        mRec.daValue:=null;

        dec(mCount);
      end;
    end else
    Raise EW3Structure.Create(CNT_ERR_STRUCTURE_INVALIDSIGN);
  finally
    mReader.free;
  end;
end;

//############################################################################
// TW3Structure
//###########################################################################

procedure TW3Structure.WriteString(name:string;
          value:String;const encode:Boolean);
begin
  (* base64 encode string to avoid possible recursion
     should someone store another JSON object as a string *)
  if encode then
  Begin
    asm
      @value = btoa(@value);
    end;
  end;
  Write(name,value);
end;

procedure TW3Structure.WriteInt(name:string;Value:Integer);
begin
  Write(name,value);
end;

procedure TW3Structure.WriteBool(name:string;value:Boolean);
begin
  Write(name,value);
end;

procedure TW3Structure.WriteFloat(name:String;value:Float);
begin
  Write(name,value);
end;

procedure TW3Structure.WriteDateTime(name:String;value:TDateTime);
begin
  Write(name,value);
end;

//############################################################################
// TW3JsonStructure
//###########################################################################

Constructor TW3JsonStructure.Create(const Data:Variant);
begin
  inherited Create;
  if not TVariant.IsNull(Data)
  and not Data.IsUnassigned then
  FBuffer:=Data else
  FBuffer:=TVariant.CreateObject;
end;

procedure TW3JsonStructure.SaveToJSON(var Data:String);
begin
  if (FBuffer<>unassigned)
  and (FBuffer<>NULL) then
  Data:=JSON.Stringify(FBuffer) else
  Data:=null;
end;

procedure TW3JsonStructure.LoadFromJSON(Value:String);
begin
  value:=trim(Value);
  if value.length>0 then
  FBuffer:=JSON.Parse(value) else
  FBuffer:=TVariant.CreateObject;
end;

procedure TW3JsonStructure.SaveToStream(Stream:TStream);
var
  mWriter:  TWriter;
  mtext:    String;
begin
  SaveToJSON(mText);
  mWriter:=TWriter.Create(Stream);
  try
    mWriter.writeString(mText);
  finally
    mWriter.free;
  end;
end;

procedure TW3JsonStructure.LoadFromStream(Stream:TStream);
var
  mText:    String;
  mReader:  TReader;
begin
  mReader:=TReader.Create(stream);
  try
    mText:=mReader.ReadString;
  finally
    mReader.free;
  end;
  LoadFromJSON(mtext);
end;

procedure TW3JsonStructure.Clear;
begin
  FBuffer:=TVariant.CreateObject;
end;

procedure TW3JsonStructure.Write(name:String;value:variant);
begin
  FBuffer[name]:=value;
end;

end.
binary code JSON Records Streams Structures WebSocket

Smart Graphics

Posted on 24.01.2013 by Jon Lennart Posted in Developers log, News

Every Delphi programmer knows how to use the canvas. Its easy, its straight forward and it can be a source of phenomenal frustration if you want to do more than draw straight lines. Good old TCanvas is, despite it’s ease of use, a dinosaur in terms of modern features. The moment you start thinking about anti-aliasing, alpha blending or anything pertaining to rotation – it’s game over for TCanvas.

A smarter canvas

Smart mobile studio implements (or wraps) the HTML5 canvas directly, which means that you have access to all the latest features. The HTML5 canvas was implemented by Apple (webkit codebase) and is the browser equivalent of their Quartz API. This means first of all that it’s a bit trickier to get going, but on the flipside once you master it you can generate some truly amazing graphical effects.

Before we dig into the canvas, i thought it might be best to get up to speed with some of the terminology you are bound to encounter. Some of the concepts are not bound directly to HTML5 but are loosely related to computer programming in general.

Double buffering

Double buffering simply means that you draw your graphics to an offscreen bitmap rather than directly onto the visible canvas. When you are finished drawing you copy (also called “blitting”) the result to the visible display in one fast operation. This technique reduces flickering and makes movement appear smooth. The reason double buffering works is because there is often a delay between your calls – and the actual pixel memory being altered by the CPU/GPU (graphical processing unit). It greatly depends on the kind of hardware you are running, but either way – double buffering is what people do.

On a side note I can mention that Delphi actually uses double buffering by default. If you look up the drawing mechanism for TWinControl you will find that Delphi allocates a new bitmap, draws the control, then copy the result onto the device context. The problem with Delphi is that it allocates a bitmap for each draw, which is extremely slow. Thankfully, we dont have to care about that under Smart Mobile Studio.

Per scene rendering

Under Delphi whenever you use the canvas and call methods like lineto, circle, ellipse etc. these functions are executed “as is”. So once you issue a call to lineTo the underlying WINAPI draws a line into the bitmap your canvas is connected to. This method is very effective, bare bone and does it’s job well. Sadly it is very tricky to create anything modern with this. It’s perfect for 1990’s user interfaces but doesnt cut it for 2013.

HTML5 doesnt really work this way (nor does quartz) because here everything is based on paths. A path is basically just an array of TPoints that you pre-calculate before anything is drawn on screen. So to draw a line you first have to call beginpath, then issue a moveto and lineto command (which we already know under delphi), and finally you draw the line with a call to stroke or endpath. Here is a code snippet from HTML5 Canvas Tutorials:

      canvas.beginPath();
      canvas.moveTo(100, 20);

      // line 1
      canvas.lineTo(200, 160);

      // quadratic curve
      canvas.quadraticCurveTo(230, 200, 250, 120);

      // bezier curve
      canvas.bezierCurveTo(290, -40, 300, 200, 400, 150);

      // line 2
      canvas.lineTo(500, 90);

      canvas.lineWidth := 5;
      canvas.strokeStyle := 'blue';
      canvas.stroke();
Paths are cool

Paths are cool

As you can probably imagine, by automating the variables involved you can really get some amazing results with very little effort. Check out this liquid particles demo for instance (click image):

Nice canvas demo

Nice canvas demo

My personal favorite JavaScript demo has to be: or so they say

Also make sure you check out the graphics demos that ship with Smart Mobile Studio for more inspiration! And remember, the smart canvas maps more or less directly to the HTML5 canvas. We have added a few helper routines to make life easier for pascal programmers (and helper classes) but you will have no problems following a HTML5 JavaScript canvas tutorial with Smart Mobile Studio.

Alpha blending

Alpha blending simply means that you can draw graphics that is semi-transparent. Typically alpha blending is associated with 32bit graphics (RGBA) where each pixel or dot on the display is represented by 4 bytes. The first 3 bytes represents red, green and blue while the last byte defines the opacity of the pixel. When you copy a bitmap onto another which uses opacity as an option, it will merge with the existing graphics rather than overlap with it.

Sprites

In the golden days of 16 bit home computers (Amiga and Atari) the hardware supported sprites. A sprite is basically just a small, transparent picture which game programmers use to display and animate characters. In our day of fast processors and high speed 3d effects – there is no longer hardware support for sprites, but the concept of a “sprite” (as a moving graphical element) is still widely used. So if someone uses the term “sprite” or “bob” (the graphical co-processor in the Amiga was called “the blitter”, hence “blitter object”) you what they are talking about.

Next article

In this first installment we have taken a quick look at related concepts that you are bound to meet when programming graphics. Concepts like double buffering, sprites, alpha blending are universal and are deployed on all platforms regardless of language. So it’s handy to get to know these concepts straight away. We have also introduced how the HTML5 canvas works, that it uses paths rather than ad-hoc, brute force like good old TCanvas.

In the next installment we will dive into Smart Mobile Studio and familiarize ourselves with the API and draw some stuff. We will further look at how each of the above concepts work, things like double buffering, in real-life.

Reference material

  • W3Schools HTML5 canvas tutorial
  • HTML5 path tutorial
  • Liquid particles demo
  • Apple Quartz API documentation
  • Or so they say JS demo
Apple code delphi graphics javascript Object Pascal pixel webkit

GradLines

Posted on 14.04.2012 by Jørn E. Angeltveit Posted in Developers log
GradLines

GradLines

Christian-W. Budde has already amazed us with two cool classical games (Tetris and Minesweeper), but Christian has still got some other goodies to share with us.  As a member of the Graphics32 libraryteam, he was inspired by the Gradient line example and created a similar solution with Smart.

Nice work, Christian.

Demo and code

You can download the project source code here:  GradLines.zip

You can find an online demo here:  GradLines demo

(Or simply scan the QR code below with your phone)

qrcode

code demo gr32 gradient gradline graphics graphics32 line

Minesweeper

Posted on 12.04.2012 by Jørn E. Angeltveit Posted in Developers log
Minesweeper

Minesweeper - kill an hour or two...

Yet another cool game implementation by Christian.

Look up for this guy in the 2nd PGD Challenge!  😉

Thank you for your contributions, Christian.

Demo and code

You can download the project source code here:  Minesweeper.zip

You can find an online demo here:  Minesweeper online demo

(Or simply scan the QR code below with your phone)

qrcode

code demo game minesweeper

Tetris arrives in Sparta

Posted on 03.04.2012 by Jon Lennart Posted in Developers log
A very nice tetris clone!

A very nice Tetris clone!

One of the beta-testers really put the system to it’s test. He received the beta – and the next day he submitted a fully blown Tetris clone to us. It is once again a nice testament to just how easy it is to port over Delphi code and make it spin under HTML5 with Smart.

So hat off to Christian! Talk about getting into the RTL quickly. I wasted my entire lunchtime playing this 🙂 Way to go, cheers!

Game coding under Smart

There are currently 2 ways of creating games under Smart. The first is naturally by creating a game project (clicking “new project” -> Game) which will establish a bare-bones HTML5 canvas application. This means no form designs and is more suitable for low-level coders and people who want to squeeze the last drop of juice out of the browser.

The second way, is to create a normal visual application and then add the unit “w3sprite3d” to the uses list. This gives you access to a class called TW3Sprite. TW3Sprite implements a javascript API called sprite3d (no dependencies, we re-created it in smart), which simply put allows you to easily rotate, scale and move the control around the screen – and it’s all done using hardware acceleration (see older posts about Sprite3d and also check out the docs for the library if you are unsure about it).

I also took the liberty to speed up Sprite3d a bit, using and/or operators rather than ad-hoc string replacements. So you should get better speed under Smart.

Depending on your game type, either solution will serve you well – and you will have a serious advantage over classical JS programmers which must write tons of code to get the same level of control and infrastructure.

For a look at what Sprite3d can do, have a look at this article:  Retro demo coded in Smart

Demo and code

You can download the project source code here:  Tetris.zip

You can find an online demo here:  Tetris demo

(Or simply scan the QR code below with your phone)

qrcode

code demo game tetris

Pages

  • About
  • Feature Matrix
  • Forums
  • News
  • Release History
  • Download
  • Showcases
    • The Smart Contest 2013, Round 1 – Graphics
  • Store
  • Documentation
    • Creating your own controls
    • Debugging, exceptions and error handling
    • Differences between Delphi and Smart
    • Get the book
    • Getting started
      • Introduction
      • Local storage, session storage and global storage
      • Application architecture
      • The application object
      • Forms and navigation
      • Message dialogs
      • pmSmart Box Model
      • Themes and styles
    • Layout manager
    • Networking
      • Loading files
      • TW3HttpRequest
      • TW3JSONP
    • Prerequisites
    • Real data, talking to sqLite
    • System requirements
    • Project types
      • Visual project
      • Game project
      • Console project

Archives

  • December 2019
  • December 2018
  • November 2018
  • July 2018
  • June 2018
  • February 2018
  • September 2017
  • April 2017
  • November 2016
  • October 2016
  • September 2016
  • April 2016
  • March 2016
  • January 2016
  • October 2015
  • September 2015
  • July 2015
  • April 2015
  • January 2015
  • December 2014
  • October 2014
  • September 2014
  • August 2014
  • July 2014
  • June 2014
  • March 2014
  • February 2014
  • January 2014
  • December 2013
  • November 2013
  • October 2013
  • August 2013
  • July 2013
  • June 2013
  • May 2013
  • April 2013
  • March 2013
  • February 2013
  • January 2013
  • December 2012
  • November 2012
  • August 2012
  • July 2012
  • June 2012
  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • November 2011
  • October 2011
  • September 2011

Categories

  • Announcements (25)
  • Developers log (119)
  • Documentation (26)
  • News (104)
  • News and articles (16)

WordPress

  • Register
  • Log in
  • WordPress

Subscribe

  • Entries (RSS)
  • Comments (RSS)
© Optimale Systemer AS