Tuesday, February 12, 2013

Interactive dialogue for HTML5 game - part 1

In this post I do not want to deal with theories of dialogue. I will try to summarize the requirements for the implementation of dialogue in a computer game. In the next post I am going to implement such a tool.




Type of dialogs:

  • Linear
  • Linear interrupted
  • Linear dialogue with questions
  • Branched dialogue with different results
  • Fake branched dialogue with the same end
  • Procedural dialogue
  • Combined dialogue

Linear dialogue

Example:
  • Start: player: Do you know anything about the cave outside the village?
  • 1 character:   People is losing there.
  • 2 player: How to get there?
  • 3 character: Follow the river.
  • 4 player: How much time does it take path.
  • End: About 14 hour.




Linear interrupted

A player may ask follow-up questions.

Example:

  • 1 character:   People is losing there.
    • 1a player: Tell me more please.
    • 1a character: ...

  • 3 character: Follow the river.
    • 3a player: I need a guide.
    • 3a character: ...


Linear dialogue with questions

Extension topics are in a separate thread. May contain more information. Information thread can still be active, even if you repeat the dialogue. Information thread may include comprehensive encyclopedic knowledge, such as the history (Vietcong 2).




Branched dialogue with different results

Large amounts of data, even in a short dialogue.




Fake branched dialogue with the same end

The player has the feeling that the conversation affects.




Procedural dialogue

It contains variables that affect the result of conversation.





Key features


  1. Visualization (GUI tool )
  2. Conditions
  3. Variables
  4. Outgoing Links
  5. Export to JSON


1. Visualization
I am going to do a GUI tool (dynamic HTML form) for designing dialogue. GUI tool also will be able to show dialogue graph.

2. Conditions
Ability to show and hide a branch based on conditions. (See Procedural dialogue).

Example:

  • isFirstVisit == true
  • hasSword == true
  • mood >= 10
  • inventory.contains(“amulet”)

3. Variables
Can set variables, increment, decrement. (See Procedural dialogue).

Example:

  • hasSword = true
  • mood += 2

4. Outgoing Links
Each item can have a reference (0..*) to another item in the dialog.

5. Export to JSON
I am going to export data structure in JSON. Despite its relationship to JavaScript, it is language-independent, with parsers available for many languages.



Example of dialogue

Simple dialogue, but contains: links, conditions, variables.




Proposed JSON



It may interest you to know

Chat Mapper
Chat Mapper is tool for writing and testing nonlinear dialogue, especially for video games and training. Free for noncommercial use (no export).


Article
How Video Game Stories Are Written

Friday, January 18, 2013

Performance Testing with JMeter


The JMeter is desktop/ command line Java application designed to load test functional behavior and measure performance. It was originally designed for testing Web Applications.

This article shows how to use it for testing webapps.



Preparations


  • Install JMeter on your laptop. On Linux is as package in some central repositories.
  • Install htop on your server. htop is top on steroids. You can find it on rpmforge repos.


Getting Started

It shows how to define basic request for server and dump reports.

1. Adding Thread Group to Test Plan

  • Number of Threads: Defines how many threads (users) will access to the server.
  • RampUp Period: In what time period the requests shall be made. Zero means immediately.


2. Adding Reguest to Thread Group
Type in the Server name, Port number, Path.



3. Adding Listeners to Thread Group
Listeners used to capture and presentation of results.
For example: Spline Visualizer, Summary Report, View Requests in Table.




4. Starting basic test.
Go to server and run htop for watching server status dynamically. You can see: CPU and memory usage, Swap usage, processes, …

From JMeter main menu Run>Start. During testing watch the behavior of the server on htop console. It may help to understand more your server.

After completing the test explore results in Listeners sections: errors, times, responses,...


Using proxy server for recording complex requests


For a definition of complex requests is best to use the HTTP Proxy Server.
  1. Insert HTTP Proxy Server component to WorkBench fork. Define port and click to Start button.
  2. Insert Recording Controller to Thread Group.


Connecting to HTTP Proxy Server
Go into the settings of your favorite web browser and connect to the proxy server.


Now, in your web browser go to your webapp and make requests. For example fill out and submit the form. All your requests are stored in the Record Conroller.



At the end don´t forget stop the HTTP Proxy server. Start test and watch results.

Conclusion

JMeter offers a lot of others components: Timers, Logic Controllers, Assertions for checking responses. You can test SOAP and XML/RPC services, JDBC connections, FTP requests.

JMeter can be run from the command line. You can test automatically from scripts, or on server without GUI.

Thursday, December 6, 2012

Email confirmation after sending Google form

Google Apps Script is a scripting language that provides easy ways to automate tasks across Google Drive. 

This tutorial explains a script that sends an email confirmation after submitting the Google Form.

Sending email from GAS is very simple:

function sendEmail() {
    MailApp.sendEmail(“customer@gmail.com”, “Confirmation”, “Hello customer.”);
}

Usually there is a need to customize the email body. For example from Google Spreadsheet:


function sendEmail() {
    var message = “Hi ${firstname} ${lastname}, Thank you for buying gun.”
    MailApp.sendEmail( email , “Confirmation”, message);
}

After submitting Google Form script finds the last row in the spreadsheet and puts value instead of the column name. For example from ${firstname} to John.

When you want to send a comprehensive email, it might be better to use HTML email body.
function sendEmail() {    
  var message = createTemplateFromFile( TEMPLATE_FOR_CUTOMER );
  MailApp.sendEmail( email, “Confirmation”, "", {htmlBody: message});
}

HTML template for customer










And this is the idea of ​​the script. After submitting Google Form script finds last row from spreadsheet and puts value to html template. HTML template, you can change and expand as your needs. Filled template is used as email body.


Trigger
The last important task is to set the trigger. From the main menu of Script Editor click to:
Resources > All your triggers


















Source code can be downloaded from: Github.

Links


Recommendation

I was inspired by a great book Google Apps Script for Beginners


The book contains:

  • Spreadsheet automation
  • Manipulate Forms
  • Managing Email Account
  • Script in text document
  • Standalone Web application

Sunday, December 2, 2012

Import Gaelyk project to Eclipse IDE

Gaelyk is a lightweight Groovy toolkit for Google App Engine Java and have a good documentation.

Since the Musketyr published Gradl-gaelyk-eclipse-plugin, we can develop a Gaelyk project in comfort of Eclipse IDE.

This tutorial shows how to start a Gaelyk project in Eclipse.


Course of action



  1. Download Gaelyk Template project
  2. Fix gradle.build
  3. Import project to Eclipse
  4. Set project WAR directory
  5. Set App Engine
  6. Refresh Gradle dependencies
  7. Run project




Download Gaelyk template project


You can download Gaelyk Template project from Gaelyk website or visit Gaelyk on Github. The current version - v1.2 - of Template project on Gaelyk website contains a build problem, which is already fixed, but it is not included in zip package of the Template project on Gaelyk websites.





Fix gradle.build


After downloading the package, it is necessary to change the file gradle.build.

eclipse { 
  classpath { 
    plusConfigurations += configurations.functionalTestRuntime 
  } 
} 


Import project to Eclipse


Import the project into Eclipse IDE with Gradle plugin:

File > Import






Set project WAR directory


After import set project WAR directory:




Set App Engine




Refresh Gradle dependencies


Next step is refresh dependencies:

Right click on Project name > Gradle > Refresh All



Run project


Then you run the project as a Web Application:

Right click on Project name > Run As > Web Application



Links



Monday, April 25, 2011

DCS-950G streaming in Linux

Yesterday I got IPcam DCS-950G. I wanted to connect camera to Motion but it did not get stream. I had to use stupid IE only. I was angry and looking for solution. I found people just as disappointed as I am. I decided to solve this problem.

I went to D-Link and study specification. After that I downgrade camera to DCS-950G_ A1_Firmware_v1.00 because the camera with this old firmware does not need admin authentication for streaming. It's so convenient. I do not have to send with each request the password.

I wanted to write a Groovy script, but I wanted to control the camera from the router, which I do not have Java. That's why I chose Bash.

After hours of testing, I had written a working script:

#!/bin/bash
#

WEBCAM_IP="192.168.0.20"

#######################################################################

#init
{ exec 3<>/dev/tcp/${WEBCAM_IP}/5000; echo -n "ARAGORN_INIT" >&3; cat <&3> /dev/null; } &

sleep 2

#start
exec 3<>/dev/tcp/${WEBCAM_IP}/5001
echo -n "ARAGORN_START#255055293901165#0#1#0" >&3

#data
while :
do
 
    head -c 40 <&3 > header.hex
    BYTES=( `hexdump -v -s 24 -n 4 -e ' 1/1 "%02X " ' header.hex` )      
    HEX="${BYTES[3]}${BYTES[2]}${BYTES[1]}${BYTES[0]}"   
    DATA_LENGTH=`echo "obase=10; ibase=16; ${HEX}" | bc`  
    head -v -c "${DATA_LENGTH}" <&3
                                
done


With MPlayer I can play the stream directly from the camera. Mplayer takes around 5% CPU on a single camera. 
./dcs-950G.bash | mplayer - -demuxer mpeg4es


With ffmpeg I got every second  actual jpeg for Motion.

Saturday, March 12, 2011

JavaFX game: Wolfs attack

I this article I develop a JavaFX game in Netbeans. You can see result of me game:

I wont deploy game for mobile phone. I try on the game in mobile emulator in Netbeans on Windows. It run fine. In Linux we have not mobile emulator yet (28.11.2009).
The source code of this game as Netbeans project are here.
Thanks for your comment under article.

Graphics

For create graphics I use Inkscape (0.47).You can look find more about JavaFX and Inkscape for example in Silveira Neto. But Inkscape 0.47 was release yet and You can not compile source code of Inkscape.

At the end I export images wolfs and sheep from svg format to png. As splash image I let svg format export in Inkscape to JavaFX class, but I was supprised that not more difficult svg image have a lots rows in JavaFX class. About 20 tausend. That big class is not work well in Netbeans editor.
Source graphics.svg file.

JavaFX class

I mean that in me game is this good ideas:

  • Collision detection from Silveira Neto.

  • Switch between splash and game screen use in Brick JavaFX game.
Let me introduce the code.

Config.fx

All game setting is in Config.fx file. You can see setting as scene width and height, some images path, animation time, game speed and etc.
public def SCENE_WIDTH = 240;
public def SCENE_HEIGHT = 320;
public def SCENE_INFOPANEL_HEIGHT = 25;
public def MARGIN = 5;

public def WOLF_IMAGE_WIDTH = 100;
public def WOLF_IMAGE_HEIGHT = 50;
public def SHEEP_IMAGE_WIDTH = 50;
public def SHEEP_IMAGE_HEIGHT = 50;

public def ANIMATION_TIME = 0.04s;

public def COUNT_OF_LIVE = 3;

public def SHEEP_IMAGES = [ Image {url: "{__DIR__}sheep_waiting.png"},
Image {url: "{__DIR__}sheep_lu.png"  },   // left up
Image {url: "{__DIR__}sheep_ld.png"  },   // left down
Image {url: "{__DIR__}sheep_ru.png"  },   // right up
Image {url: "{__DIR__}sheep_rd.png"  }    // right down
];

public def WOLF_IMAGES = [
Image {url: "{__DIR__}wolf_jump1_left.png"  },
Image {url: "{__DIR__}wolf_jump2_left.png"  },
Image {url: "{__DIR__}wolf_jump3_left.png"  },
Image {url: "{__DIR__}wolf_jump1_right.png"  },
Image {url: "{__DIR__}wolf_jump2_right.png"  },
Image {url: "{__DIR__}wolf_jump3_right.png"  }
];

//--------------------------------WOLFS
public def WAITING_DIRECTION = 0;
public def LEFT_UP_DIRECTION = 7;
public def LEFT_DOWN_DIRECTION = 1;
public def RIGHT_UP_DIRECTION = 9;
public def RIGHT_DOWN_DIRECTION = 3;

public def WOLFS_AGGRESSIVENESS = 100;
public def WOLF_SPEED = 1000;

Wolf.fx

Class Wolf has two timelines. First for jump wolf to sheep in timeline attack.
In this timeline I define path where will bee wolf jump. You can set the direction of path when the instance of class Wolf create. The second timeline move I set image cyklus for sprite.
Wolf has function start and stop. This function starting and stopping mentioned timelines.
Wolf has important function wantAttack():Boolean in which it decide when wolf start attack. This function use Random.
public class Wolf extends CustomNode{ 

    public var image:Image;
    public-init var attackPath:Path;
    public var direction:Integer;

    var aggressiveness = Config.WOLFS_AGGRESSIVENESS;
    var random : Random = new Random();
    var frame = 0;
   
    public function start() {       
        move.play();
        attack.playFromStart();
    }

    public function stop() {
        move.stop();
        attack.stop();
    }
   
    protected override function create(): Node {
        return Group {
          content: [
                ImageView{
                          image: bind image;
                          }
          ]
        } // Group
    }

    public function wantAttack():Boolean{
        if ( (not attack.running) and random.nextInt( aggressiveness ) == 0){        
            return true; //==========>
        }
        return false;
    }

    public def attack = PathTransition {
                   node: this
                   path: bind AnimationPath.createFromPath(attackPath)
                   orientation: OrientationType.NONE;
                   interpolator: Interpolator.EASEIN
                   duration: Duration.valueOf( random.nextInt( Config.WOLF_SPEED) + 1000 );
                   repeatCount: 1
                   autoReverse: true              
                   action: function() {                       
                       Main.mainFrame.lifeCount--;                     
                    }
    };



    def move = Timeline {
        repeatCount: Timeline.INDEFINITE
        keyFrames: KeyFrame {
            time : 1s/8
            action: function() {

                    if(direction.equals(Config.LEFT_UP_DIRECTION) or direction.equals(Config.LEFT_DOWN_DIRECTION)){
                        image = Config.WOLF_IMAGES[ (++frame mod 3) ] ;
                    }else{
                        image = Config.WOLF_IMAGES[(++frame mod 3) + 3] ; 
                    }
            }
        }
    }
}

Sheep.fx

Class Sheep have only functions for image change. The variable direction keep info about direction where is sheep turn.
public class Sheep extends CustomNode{

public-read var image:Image;
public-read var direction:Integer;

public function waiting():Void{
    direction = Config.WAITING_DIRECTION;
    image = Config.SHEEP_IMAGES[0];
}

public function leftUp():Void{
    direction = Config.LEFT_UP_DIRECTION;
    image = Config.SHEEP_IMAGES[1];
}

public function leftDown():Void{
    direction = Config.LEFT_DOWN_DIRECTION;
    image = Config.SHEEP_IMAGES[2];
}

public function rightUp():Void{
    direction = Config.RIGHT_UP_DIRECTION;
    image = Config.SHEEP_IMAGES[3];
}

public function rightDown():Void{
    direction = Config.RIGHT_DOWN_DIRECTION;
    image = Config.SHEEP_IMAGES[4];
}


protected override function create(): Node {
          Group {
                content: [
                      ImageView {                               
                                image:bind image;
                        }
                ]
       } // Group
  }
}

Splash.fx

Class content splash image. It contents function start() and stop() where You can add some timelines as in Brick game. I use svg image exported from Inkscape as I mentioned above.
public class Splash extends CustomNode{ 

   def intro = Intro{};

    def background = Group{
            focusTraversable: true;
            content:[
                    Rectangle {
                            x:0;
                            y:0;
                            width:Config.SCENE_WIDTH;
                            height: Config.SCENE_HEIGHT;
                            fill: Color.web("#00bfff");
                     },                  
                     intro
                    ]
            onKeyPressed: function( e: KeyEvent ):Void {
                Main.mainFrame.startGame(Config.COUNT_OF_LIVE);
            }
   }


  public function start(){
    background.requestFocus();
  }

  public function stop(){

  }
 
  override public function create(): Node {
        Group {
            content: [
                background
            ]
        };
    }
}

Level.fx

This is class for game logic. There is class Sheep and Wolfs construct. Every Wolf has different attackPath and direction. There are function start() and stop() for play main timelines: gameLogics. In this timeline is function checkWolfsAttack(wolfs) who check Wolfs will attack. There is also collision detection as I mentioned above.
public class Level extends CustomNode{

   var state = 0;
     
   def textGameOver = Text{
                        translateX:Config.SCENE_WIDTH /4;
                        translateY:Config.SCENE_HEIGHT/4;
                        font: Font.font("SansSerif",FontWeight.BOLD,20)
                        content: "GAME OVER.";
                        visible:false;
                        }

   def infoPanel = InfoPanel{};

   var hill = Arc {
                   centerX: Config.SCENE_WIDTH/2;
                   centerY: Config.SCENE_HEIGHT;
                   radiusX: Config.SCENE_WIDTH/3;
                   radiusY: Config.SCENE_HEIGHT/3;
                   startAngle: 0;
                   length: 180;
                   type: ArcType.OPEN
                   fill: Color.GREEN
           }

   var sheep = Sheep{
                translateX:Config.SCENE_WIDTH /2 - Config.SHEEP_IMAGE_WIDTH /2;
                translateY:(Config.SCENE_HEIGHT - Config.SCENE_HEIGHT/3)  - Config.SHEEP_IMAGE_HEIGHT;
            };
    var wolf1 = Wolf{
                    direction:Config.LEFT_DOWN_DIRECTION;
                    translateX:- Config.WOLF_IMAGE_WIDTH; //outside
                    attackPath:Path{
                        elements: [
                              MoveTo { x:-Config.WOLF_IMAGE_WIDTH  y: (Config.SCENE_HEIGHT - Config.SCENE_INFOPANEL_HEIGHT) - Config.WOLF_IMAGE_HEIGHT/2 },
                              QuadCurveTo { x: Config.SCENE_WIDTH /2;
                                            y: (Config.SCENE_HEIGHT - Config.SCENE_HEIGHT/3)- Config.WOLF_IMAGE_HEIGHT/2;
                                            controlX: Config.SCENE_WIDTH /6;
                                            controlY: (Config.SCENE_HEIGHT - Config.SCENE_HEIGHT/3)- Config.WOLF_IMAGE_HEIGHT/2;
                                           }
                                 ]
                            }
                    };
    var wolf2 = Wolf{
                    direction:Config.LEFT_UP_DIRECTION;
                    translateX:- Config.WOLF_IMAGE_WIDTH; //outside
                    attackPath:Path{
                        elements: [
                              MoveTo { x:-Config.WOLF_IMAGE_WIDTH    y: Config.WOLF_IMAGE_HEIGHT/2 },
                              QuadCurveTo { x: Config.SCENE_WIDTH /2;
                                            y: (Config.SCENE_HEIGHT - Config.SCENE_HEIGHT/3)- Config.WOLF_IMAGE_HEIGHT/2;
                                            controlX: Config.SCENE_WIDTH/2;
                                            controlY: Config.WOLF_IMAGE_HEIGHT;
                                           }
                                 ]
                            }
                    };
    var wolf3 = Wolf{
                    direction:Config.RIGHT_UP_DIRECTION;
                    translateX:- Config.WOLF_IMAGE_WIDTH; //outside
                    attackPath:Path{
                        elements: [
                              MoveTo { x: Config.SCENE_WIDTH + Config.WOLF_IMAGE_WIDTH  y: Config.WOLF_IMAGE_HEIGHT/2 },
                              QuadCurveTo { x: Config.SCENE_WIDTH /2;
                                            y: (Config.SCENE_HEIGHT - Config.SCENE_HEIGHT/3)- Config.SHEEP_IMAGE_HEIGHT/2;
                                            controlX: Config.SCENE_WIDTH/2;
                                            controlY: Config.WOLF_IMAGE_HEIGHT;
                                           }
                                 ]
                            }
                    };
    var wolf4 = Wolf{
                    direction:Config.RIGHT_DOWN_DIRECTION;
                    translateX:- Config.WOLF_IMAGE_WIDTH; //outside
                    attackPath:Path{
                        elements: [
                              MoveTo { x: Config.SCENE_WIDTH + Config.WOLF_IMAGE_WIDTH  y: (Config.SCENE_HEIGHT - Config.SCENE_INFOPANEL_HEIGHT) - Config.WOLF_IMAGE_HEIGHT/2 },
                              QuadCurveTo { x: Config.SCENE_WIDTH /2;
                                            y: (Config.SCENE_HEIGHT - Config.SCENE_HEIGHT/3)- Config.WOLF_IMAGE_HEIGHT/2;
                                            controlX: Config.SCENE_WIDTH  - Config.SCENE_WIDTH /6;
                                            controlY: (Config.SCENE_HEIGHT - Config.SCENE_HEIGHT/3) - Config.WOLF_IMAGE_HEIGHT/2;
                                           }
                                 ]
                            }
                    };
    var wolfs: Wolf[] = [wolf1,wolf2,wolf3,wolf4];
    var group: Group;

    public function start() {      
        gameLogics.play();
        group.content[0].requestFocus();
        state = 2;
    }

    public function stop() {       
        gameLogics.stop();
    }
      
    def gameLogics = Timeline {
                            repeatCount: Timeline.INDEFINITE
                            keyFrames: KeyFrame {
                                                time : Config.ANIMATION_TIME;
                                                action: function() {                                                       

                                                            if (state != 2) {
                                                               return; //==========>
                                                            }
                                                            
                                                            if (Main.mainFrame.lifeCount == 0){
                                                                gameOver();
                                                            }

                                                            checkWolfsAttack(wolfs);
                                                        }
                                                }
                            };
  
   override public function create(): Node {
        group = Group {
            content: [
                Rectangle{
                        focusTraversable: true
                         x:0;
                         y:0;
                         width:Config.SCENE_WIDTH;
                         height:Config.SCENE_HEIGHT;
                         fill: Color.web("#00bfff");
                                     
                    onKeyPressed: function( e: KeyEvent ):Void {
                      
                        //skip to begin
                        if (state == 3 and e.code == KeyCode.VK_5){
                            Main.mainFrame.state = 0;
                        }
                      
                        if (e.code == KeyCode.VK_7) {
                                sheep.leftUp();
                                                              
                        } else if (e.code == KeyCode.VK_1) {
                                sheep.leftDown();
                                                               
                        }else if (e.code == KeyCode.VK_9) {
                                sheep.rightUp();
                                                               
                        }else if (e.code == KeyCode.VK_3) {
                                sheep.rightDown();
                        }

                        checkCollision(wolfs);
                    }

                    onKeyReleased: function( e: KeyEvent ):Void {                              
                                sheep.waiting();

                    }
                },

                 hill, sheep, wolf1, wolf2, wolf3, wolf4,  infoPanel, textGameOver

                    ]
        }
     }
     
    function checkCollision(wolfs:Wolf[]):Void{ 
             for(wolf in wolfs){
                if(wolf.attack.running and sheep.direction.equals(wolf.direction) and isCollision(wolf)){   
                        hit(wolf);
                }
             }      
     }
   
     function isCollision(wolf:Wolf): Boolean {
        return (collision(wolf.translateX, wolf.translateY, wolf.translateX + wolf.image.width, wolf.translateY + wolf.image.height, sheep.translateX, sheep.translateY, sheep.translateX + sheep.image.width, sheep.translateY + sheep.image.height));
     }

     function collision(ax, ay, bx, by, cx, cy, dx, dy): Boolean {
        return not ((ax > dx)or(bx < cx)or(ay > dy)or(by < cy));
     }

     function hit(wolf:Wolf):Void{
        wolf.stop();
        wolf.translateX = - Config.WOLF_IMAGE_WIDTH;
        Main.mainFrame.score++;
     }

     function checkWolfsAttack(wolfs:Wolf[]){
        for(wolf in wolfs){                
            if (wolf.wantAttack()){                
                wolf.start();
            }
        }
     }

     function gameOver(){             
        textGameOver.visible = true;
        sheep.visible = false;
        for (wolf: Wolf in wolfs){
            wolf.visible = false;
        }
        state = 3;
     }         
}

Main.fx

You can see switch between splash and level
public var mainFrame: MainFrame;

function run(__ARGS__ : String[]) {

    mainFrame = MainFrame {
        title: "Wolfs attaks"
        resizable: false
        scene: Scene {
            width:Config.SCENE_WIDTH;
            height:Config.SCENE_HEIGHT;
        }
    }
}

public class MainFrame extends Stage {

    // Instance of splash (if exists)
    var splash: Splash;

    // Instance of level (if exists)
    var level: Level;

    // Number of lifes
    public var lifeCount: Integer;

    // Current score
    public var score: Integer;

    // Initializes game (lifes, scores etc)
    public function startGame(lifeCount:Integer) { 
        this.lifeCount = lifeCount;
        score = 0;
        state = 1;
    }

    // Current state of the game. The next values are available
    // 0 - Splash
    // 1 - Level
    public var state: Integer = 0 on replace {

        if (state < 1 ) {
            splash.stop();
            level.stop();

            level = null;
            splash = Splash {};


            scene.content = [
                splash
            ];

            splash.start();

        } else {
            level.stop();
            splash = null;
            level = Level {}

            scene.content = [
                level
            ];

            level.start();
        }
    };
}

Conclusion

Game run fain in mobile emulator in Netbeans. On real device we must wait yet. I look forward my new mobile phone will be support JavaFX profile.

Sunday, September 5, 2010

Google Web Toolkit RPC

Google Web Toolkit
  • GWT Java-to-JavaScript Compiler
  • JRE emulation library
  • GWT web UI
  • Development tools (Hosted web browser, shell,..)
  • RPC

Communicating with the server
  • RPC
  • XML
  • JSON

Packages

 


Making GWT Remote Procedure Calls

 



Modul

 



UI

package cz.kibo.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.TextBox;

public class SayHelloEntryPoint implements EntryPoint {

    private TextBox name = new TextBox();  
    private Label response = new Label();
    private Button button = new Button("Send");

    private HelloServiceAsync service;
    private AsyncCallback serviceCallback = new AsyncCallback() {
           public void onSuccess(Object result) {
              String string = (String) result;               
              response.setText(string);
           }

           public void onFailure(Throwable caught) {
               response.setText("There was an error: " + caught.toString());
           }
    };

    /**
    * Creates a new instance of MainEntryPoint
    */
    public SayHelloEntryPoint() {
    }

    /**
    * The entry point method, called automatically by loading a module
    * that declares an implementing class as an entry-point
    */
    public void onModuleLoad() {
     
       //Obtain Async service for interface
       service = GWT.create(HelloService.class);

       //go to URL
       //or use @RemoteServiceRelativePath("hello")
       ServiceDefTarget endpoint = (ServiceDefTarget) service;
       endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() + "hello");


       RootPanel root = RootPanel.get("content");       
       root.add(new Label("Name"));
       root.add(name);     

       // Listen for mouse events on the Add button.
       button.addClickHandler(new ClickHandler() {
             public void onClick(ClickEvent event) {
                   service.sayHello(new Person(name.getText()), serviceCallback);
             }
       });

       root.add(button);
       root.add(response);

    }
}


Service
  • extends RemoteService
package cz.kibo.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

//@RemoteServiceRelativePath("hello")
public interface HelloService extends RemoteService
{
    String sayHello(Person p);

}

AsyncService
  • return void
  • have last param AsyncCallback
package cz.kibo.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface HelloServiceAsync {
    void sayHello(Person p, AsyncCallback callback);
}

Service implementation

  • can extends RemoteServiceServlet
  • or you have to implements HelloServlet yet
package cz.kibo.server;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import cz.kibo.client.HelloService;
import cz.kibo.client.Person;

public class HelloServiceImpl extends RemoteServiceServlet implements HelloService{

    public String sayHello(Person p) {
       return "Hello " + p.name;
    }
}

RemoteServiceServlet
  • getThreadLocalRequest() 
  • getThreadLocalResponse()
  • onBeforeRequestDeserialized (String) 
  • onAfterResponseSerialized (String) 
  • shouldCompressResponse (HttpServletRequest, HttpServletResponse, String)
  • processCall(String)



Model
  • implements Serializable or IsSerializable
package cz.kibo.client;

import java.io.Serializable;

public class Person implements Serializable{

    public String name;
  
    public Person(){
              this(null);
    }

    public Person(String name) {
          super();
          this.name = name;      
    }
}

Netbeans project