XDView

From Jocly Wiki
Jump to: navigation, search

XDView is a Jocly Game API in charge exclusively of the user interface. It sits on top of the View methods described in Jocly Basics and provides an abstract layer to manipulate displayed objects, in particular to handle 2D and 3D interfaces in a same way (2D/3D View => XDView). It also provides a simple way to describe alternative skins, by simply specifying what changed from the 2D or 3D default.

In order to comply with the XDView interface, the View part of a Jocly game must implement the following methods:


xdv methods

All XDView methods take xdv as the first parameter. This is a utility object that provides methods to manipulate the objects displayed in the board scene whether it is in 2D or 3D mode. xdv offers 2 main methods:

  • <a name="creategadget"></a>xdv.createGadget(id, specs): creates an object displayable in the scene
  • <a name="updategadget"></a>xdv.updateGadget(id, specs [, delay [, completeFn ]]): update object properties. Optionally the properties can be changed over a period of time (in milliseconds) to create an animation if delay is specified and a developer-provided callback is called once the animation is complete

A Gadget in Jocly is an abstract object that can be displayed in the scene or, if not displayed, at least can be clicked. From the Gadget definition, the XDView machinery creates Avatars which are the actual representation of the object in the scene. For instance, a gadget can be defined such that when displayed in 2D, a <div> is created in the DOM, while in 3D, it is a mesh with its geometry and texture.

Both xdv main methods take id and specs as arguments.

id is a string that identifies uniquely a gadget. In many Jocly games, you may find a board id to describe the board the game takes place on, several piece#0, piece#1, ... to represent the pieces that move on the board, cell#0, cell#1, ... to handle clickable positions on the board "squares".

specs is a javascript object that describes the gadget properties. This object can have those keys:

  • base: hold properties common to all modes
  • 2d: properties common to all 2D skins
  • 3d: properties common to all 3D skins
  • other keys representing the name of defined skins

Let's see an example:

xdv.updateGadget("piece#42",{
    base: {
        visible: true,
        x: 1000,
        y: 3000,
    },
    "2d": {
        opacity: .5,
    },
    "3d": {
        z: 2000,
    },
    "fancy-skin-3d": {
        z: 4000,
        scale: [1,1,2],
    },
});

This indicates that gadget piece#42 will be made visible (if not already) and moved to position (1000,3000). If the current skin is 2D-based, it will be displayed as semi-transparent (opacity: .5). If the current skin is in 3D, the z coordinate (the altitude) will be set to 2000. However, if the user selected the skin called fancy-skin-3d (an alternative skin provided by the developer), the used z property will be 4000 instead of 2000. Additionally, the object will be resized with a scale of 1 on x and y axis, scale 2 on the z axis.

xdv offer 3 other methods that can be used:

  • <a name="removegadget"></a>xdv.removeGadget(id): delete a gadget previously created with xdv.createGadget(). This might be useful if you have no control over the number of instances of a given gadget class. In this case, gadgets can be created and removed dynamically. However, most of the times, it is preferable to create all gadgets at initialization and change the visible property to make them show and hide
  • <a name="savegadgetprops"></a>xdv.saveGadgetProps(id, props, saveName): stores the properties specified in props (as an array of strings) under the name saveName
  • <a name="restoregadgetprops"></a>xdv.restoreGadgetProps(id, saveName [, delay [, callback ]]): restore all gadget properties that were previously saved with xdv.saveGadgetProps(). The properties can be restored progressively if delay (in milliseconds) is specified, in order to create an animation. The callback is called at the end of the animation.

XDView coordinates

Placing pieces on the board at specified locations is of course very important when designing a game user interface. XDView makes specifying positions and dimensions as painless as possible for the developer. In particular, it is designed such that all objects use a fixed coordinate system that do not depend on the actual size of the board display area, whether the game is shown full screen or in a tiny rectangle in a web page. It also unify the plan coordinates (X and Y) so that for most games, X and Y coordinates are defined under base rather than being specialized for 2D and 3D modes.

Coordinates are always relative to the center of the screen. For instance, a gadget set up with x=-4000 and y=4000 will appear (roughly) at the bottom left of the screen in 2D and 3D (when the camera is located above the board). This prevents the need to calculate margins in order to position an object.

The width and height of the displayed area are such that it can contain a 12600x12600 square. Since, the coordinates base is centered, the X and Y values are generally between -6300 and 6300.

In some occasions, when manipulating 3D objects, it is necessary to deal with real coordinates. It this case, it is important to remember that y and z coordinates are inverted (top is actually along the Y axis) and there is a factor 1000 to take into account (1000 XDView units = 1 real unit).

Avatars classes and properties

When creating a gadget using the xdv.createGadget(id, specs) method, a type property must be specified. This indicates the kind of object that must be inserted into the scene. In general, the type is different depending on whether the user runs a 2D skin or a 3D skin. It is perfectly safe to only define a type for only one skin kind, in that case the object will not appear in other skin kinds. This might be useful for decoration objects which may only make sense in a 3D scene for instance.

The various Avatar types and their hierarchy (class-sense) and available properties are shown in this diagram:

Xd-view-avatars.svg

element

This represents a HTML DOM element.

  • x: the X coordinate of the element
  • y: the Y coordinate of the element
  • z: the z-index CSS property of the element. Higher values make the elements appear on top of lower values.
  • width: the width of the element
  • height: the height of the element
  • tag: a string representing the HTML tag to be used to create the element
  • opacity: a 0 to 1 float value (0=transparent, 1=opaque)
  • rotate: the rotation angle for the element in degrees
  • css: an object where keys represent CSS style keywords, values are CSS style values
  • classes: the CSS classes to apply to the element, separated by a space character
  • initialClasses: the permanent CSS classes to apply to the element (they won't be overridden when updating the classes property)

image

This represents an image to be displayed in the element. It occupies the entire element surface, not respecting the original image aspect ratio.

  • file: the URL for the source image. It is generally constructed using:

    xdv.createGadget("my-object",{
        "2d": {
            type: "image",
            file: this.mViewOptions.fullPath+"/res/my-image.png",
        },
    });

disk

This avatar class displays a filled circle. There are generally better ways to display that kind of objects than using the disk avatar.

canvas

This represents an element based on the HTML canvas tag.

  • draw: a function that will be called whenever the object is to be redrawn. It is called with 2 parameters:
  • ctx: the canvas context to be used for drawing. This context has already been scaled and translated such that coordinates (0,0) are located at the center of the element
  • pixSize: the number of virtual units for a real pixel. This might be useful if you want to draw a line that is say 1 pixel wide

Example:

xdv.createGadget("my-object",{
    "2d": {
        type: "canvas",
        width: 1000,
        height: 1000,
        draw: function(ctx,pixSize) {
            ctx.lineWidth=pixSize;
            ctx.moveTo(-500,-500);
            ctx.lineTo(500,500);
            ctx.moveTo(500,-500);
            ctx.lineTo(-500,500);
        },
    },
});

sprite

A sprite gadget displays only a specified area of an image as an avatar. It is often very convenient and efficient to group a number of small images into a single larger one, like a set of pieces.

  • file: the source file of the image. For instance, file: aGame.mViewOptions.fullPath+"/res/my-image.png"
  • clipwidth: the width in pixels of the area to take from the original image
  • clipheight: the height in pixels of the area to take from the original image
  • clipx: the x coordinate in pixels of the left of the area
  • clipy: the y coordinate in pixels of the top of the area

hexagon

This object draws an hexagon.

  • radius: the radius of the smallest circle that can contain the hexagon
  • lineWidthFactor: the weight of the hexagon line. 1 means 1 pixel

GadgetObject3D

The base class for 3D objects. This class is never to be instantiated.

  • x: the X coordinate
  • y: the Y coordinate
  • z: the Z coordinate
  • color: the object color (#ff0000 is pure red). Note that this property is often overridden by the texture applied to the object
  • castShadow: whether this object must have a shadow
  • receiveShadow: whether this object must show shadows generated from other objects

GadgetMesh

The base class for 3D objects representing a mesh. This class is never to be instantiated.

  • rotate: the rotation of the mesh along the Z axis
  • rotateX: the rotation of the mesh along the X axis
  • rotateY: the rotation of the mesh along the Y axis
  • scale: a scaling that can be applied to the mesh. This is an array of 3 numbers representing the scaling along axis X, Y and Z
  • materials: an object representing the materials to be applied to the mesh. The keys represent the material names, the value is an object defining the properties of the corresponding material. Those properties are defined in Three.js Material section and sub-classes
  • smooth: the number of smoothing passes that must be applied to the mesh. Remember that increasing the smoothing raises the number of polygons to be applied. It's generally not a good idea to go above 2. If a good texture is being applied to the mesh, the smooth should remain unchanged (0)
  • opacity: a 0 to 1 float representing the opacity of the mesh
  • flatShading: by default (false) the displayed objects are rendered with softened edges. If set to true, they will be left sharp
  • morphing: the array of weights for each key frame to display the actual object: A mesh may hold a number of key frames. The displayed object is defined by the weight of each of these key frames. This property is very useful to animate a mesh shape (independently of moving the whole mesh inside the scene)

camera3d

This represents the camera in the 3D scene. It must never be instantiated by the developer as the gadget is automatically created by system under id camera.

  • targetX: the X coordinate the camera is looking at
  • targetY: the Y coordinate the camera is looking at
  • targetZ: the Z coordinate the camera is looking at

custommesh3d

This allows the developer to create a custom 3D mesh object.

  • create: a function that creates the 3D object. It is invoked with a single parameter callback. Either the function returns the created object or, if it needs to load resources in order to create the object for instance, the function returns null and invokes the callback later with the created object as unique argument
  • display: a function invoked whenever xdv.updateGadget() has been called, invoked with parameters
  • force: boolean, if set to true, redisplay must be performed regardless of whether the properties have changed
  • options: an object containing the properties to setup
  • delay: the timing in milliseconds to make the changes progressively
From within the display function, it is possible to call this.replaceMesh(mesh,options,delay) in order to replace the mesh object (while keeping the same gadget). This is used for instance to change the mesh of a chess piece that has been promoted.

videofile3d

An avatar to display a video movie inside the 3D scene.

  • src: the URL of a webm video to be displayed
  • makeMesh: if not overridden, this function creates a 3D plane to display the video on. The function can be overridden by a developer-provided function taking a texture as parameter. It must create and return a mesh using that texture
  • width: the default makeMesh function uses this value (in real dimension, 1 real unit = 1000 XDView units) to set the with the plane object receiving the video
  • height: like width but for the height

plane3d

This represents a plane object.

  • sx: the width of the plane
  • sy: the height of the plane
  • texture: a Three.js texture object to paint the plane with
  • side: set to 2 for double sided plane (texture is applied on both sides)
  • material: "phong" for Phong material or "basic"

meshfile

This creates a 3D object from a mesh file.

  • file: the URL of the mesh .js file

video3d

This is used to create a 3D object to display the local or remote webcam on.

  • playerSide: 1 or -1, respectively first and second player. The system uses this information to determine which video stream (local or remote) to paint on the mesh
  • makeMesh: if not overridden, this function creates a 3D plane to display the video on. The function can be overridden by a developer-provided function taking a texture as parameter. It must create and return a mesh using that texture
  • ccv: whether face detection is to be used
  • ccvLocked: a function being called by the system with a single boolean that indicates whether face detection succeeded
  • ccvMargin: a 4 float array representing the margins to be used to increase the surface of the face detection. Default is [.1,.1,.3,.1]
  • ccvWidth: the width to reduce the image to for running the face detection algorithm
  • ccvHeight: same as ccvWidth for the height
  • hideBeforeFirstLock: if set (the default), the entire 3D object is hidden while the face detection is not succeeding, then automatically shown on the first detection

XDView interface

Those methods must be implemented into the View part of the game javascript code.

View.Game.xdInit(xdv)

xdInit() is called only once, at the very beginning of a game play. It is generally a good place where to create gadgets using the xdv.createGadget() method.

It is important to remember that even if xdInit is called only once with a Game object as the this keyword, the Game object may be deleted and recreated during the life of a game. It means this must not be used in anonymous functions declared with xdv.createGadget() as it may not refer anymore to the Game object you expect. If you need to access the current Game object from within an anonymous function in the xdInit() function, declare a variable currentGame global to your View module and set this variable at the beginning of the xdBuildScene() function. You can now use currentGame inside the anonymous function. For instance:
(function() {
    var currentGame;
    View.Game.xdInit = function(xdv) {
        xdv.createGadget("myobject",{
            "3d": {
                type: "custommesh3d",
                display: function() {
                    // access currentGame.myField
                }
            }
        });
        ...
    }
    View.Game.xdBuildScene = function(xdv) {
        currentGame = this;
    }
    ...
)();

View.Game.xdBuildScene(xdv)

The xdBuildScene() function is called every time the View is (re)initialized, like at the very beginning of the game play or when the skin is changed. This function should not change the pieces properties as it is a function of the Game object, but instead deal with displaying the board and other board-state-independent decoration objects.

View.Game.xdBuildScene = function(xdv) {
    xdv.updateGadget("board",{
        base: {
            visible: true,
        }
    });
}

View.Board.xdDisplay(xdv, aGame)

xdDisplay is a member function of the Board object. It must be used to display the current state of the board, like positioning the piece at their correct location. The display must be static, i.e, this is not the right place for running animations nor playing sounds (use xdPlayedMove for doing so).

View.Board.xdInput(xdv, aGame)

xdInput is in charge of running the user interface for the local human player to enter a move. It is a recent addition to the API to remove the need for having to implement xdBuildHTStateMachine() which is trickier. At the time of this documentation is being written, only the Chess and Checkers modules are using it, but it is the recommended way to implement new games.

xdInput is probably the trickiest part when implementing the XDView interface. You may want to go to the Jocly game inspector and check for examples of implementation:

  • in game Chess, file base-view.js
  • in game Draughts, file checkers-xd-view.js

xdInput is being called by Jocly internals and must return an object with the following properties:

  • initial: a game-specific javascript object provided by the developer. The actual content of the object is not interpreted by Jocly and is used in the actual game implementation to remember the state of the input (for instance, to know that a piece has been chosen to move).
  • getActions: a function that takes 2 parameters: moves (the array of compatible moves at this stage of the input) and currentInput (the object first defined in initial then modified during the input). It must return a description of the possible actions for this stage of the input.

The input of a move is defined by a sequence of actions. For instance, a chess move consists of clicking the piece to be moved, then clicking the destination (in reality we also need to handle the case of a pawn reaching the last row, so picking the piece type to promote to is a third action).

getActions returns an object where keys represent any string unique for a move (for instance a square position being clicked in Chess), and as values, the corresponding action description. An action object has the following fields:

  • moves: the array of Move objects compatible with this action. For instance, at the beginning of a Chess game, the description of the action Click b1 has a moves field holding 2 values corresponding to Na1 and Na3
  • click: the array of XDView gadget ids to install a click handler on to select this action. With the previous example of describing the Click b1 move at Chess, the array might simply contain the id of the square b1 (in the Jocly chess implementation, it would be clicker#1). However, the user may also click on the piece to be moved (piece#8) so this must be added to the array
  • view: the array of XDView gadget ids that must be made visible when this action is possible. For instance, the clicker#1 gadget which displays a frame around the square (and receive clicks)
  • highlight: a function that gives an opportunity to highlight some gadgets for the corresponding action. The function has a single parameter, mode, which has a string value of either "select" or "cancel" to distinguish between selecting the action or canceling it if it has already been selected. Typically, this function calls xdv.updateGadget() for a number of gadgets to perform the highlight operation
  • unhighlight: a function that undoes what a previous call to highlight did
  • execute: a function that typically animates the action when it has been selected. It has a single parameter, callback which is the function to be called when the animation has been executed
  • unexecute: a function that undoes what a previous call to execute, certainly after a cancel of the action, did. XDView does not support animating an undo, so the calls to xdv.updateGadget() must not have the delay parameter (i.e. only 2 parameters)
  • validate: an object that will extend currentInput if the action is chosen. For instance, it may be {from:42}, so the next time getActions is called, the currentInput parameter will have a field from with value 42

View.Board.xdBuildHTStateMachine(xdv, htsm, aGame)

xdBuildHTStateMachine() should be obsoleted soon as there is now an XDView internal implementation of this function that makes calls to xdInput() instead. You can have a look at examples from the Jocly game inspector, for games using XDView but not Chess nor Checkers based. For instance Yohoho, all Tafl games, all Men Morris, ...

View.Board.xdPlayedMove(xdv, aGame, aMove)

xdPlayedMove() is called whenever a move must be animated to the display area. Generally, when a human plays a move, the input interface already took care of making the animation, so there is no need to replay the move. So, the View definition of the game contains field animateSelfMoves set to false and xdPlayedMove() is not even called. However the function must be implemented in order to animate computer moves as well as for remote play an replay.

The function must display and animate the move passed as parameter as aMove, then, once the animation is completed, call aGame.MoveShown() to tell Jocly to move on with the game.

It is important to note that when xdPlayedMove() is called, the move has already been applied to the current (this) Board object. In many cases, the developer may prefer accessing the previous Board object, through aGame.mOldBoard.

It is a good practice to implement a function that animates a move (or part of a move) and to call this function from both xdPlayedMove() and the execute function of the corresponding action from xdInput().

View.Board.xdShowEnd(xdv, aGame)

This function is optionally implemented. It is used to animate the end of a game, for instance in an alignment game like Four in a row, to flash the winning lines. Once the end animation is complete, the function must call aGame.EndShown().