Tutorials
Pull-to-refresh with Phonegap
0It’s been a while since my last post. I’ve been working on some projects that are quite time-consuming; that’s why I can’t (despite having 3 prototypes) work much longer on games for the one game a month challenge.
For one of my apps using Phonegap and JQuery Mobile, I needed a list with the “pull to refresh” fonctionnality. After somes searchs and tests, I ended up using the Jquery Mobile iscrollview widget, that works pretty well.
So here is a quick start for this feature.
First of all, what is this widget for ?
This widget is a JQueryMobile version of the iScroll widget.
According to the autor website :
The script development began because mobile webkit (on iPhone, iPad, Android) does not provide a native way to scroll content inside a fixed width/height element.
By the way, this plugin allows you to use a lot of features like :
- Pinch / Zoom
- Pull up/down to refresh
- Improved speed and momentum
- Snap to element
- Customizable scrollbars
The code
Assuming that you have a Phonegap project already initialized, you need to add to your main html file :
<link rel="stylesheet" href="css/jquery.mobile.iscrollview.css"/> <link rel="stylesheet" href="css/jquery.mobile.iscrollview-pull.css"/> <script src="js/iscroll.js" type="text/javascript"></script> <script src="js/jquery.mobile.iscrollview.js" type="text/javascript"></script> |
And a page like this :
<div data-role="page" id="main" data-position="fixed"> <div data-role="header"> <h1>Test iScroll</h1> </div> <div data-iscroll="" data-role="content" class="iscroll-wrapper"> <div class="iscroll-pulldown"> <span class="iscroll-pull-icon"></span> <span class="iscroll-pull-label"></span> </div> <ul data-role="listview"> <li>Item 1 culpa aut nam qui</li> <li>Item 2 minima quam temporibus quidem</li> <li>Item 3 commodi sint facilis numquam</li> </ul> <div class="iscroll-pullup"> <span class="iscroll-pull-icon"></span> <span class="iscroll-pull-label"></span> </div> </div> </div> |
The “list-view” inside the “data-iscroll” tag will now have the “pull to refresh” feature.
If you need to do some actions (like refresh the content, …) you have to listen for some events :
var document = untyped __js__("document"); document.addEventListener("deviceready", function(e) { new JQuery(function() { new JQuery(".iscroll-wrapper").bind( { iscroll_onpulldown: onPullDown, iscroll_onpullup: onPullUp }); }); }); |
Here is the complete list of events for the pull-to-refresh feature :
- iscroll_onpulldown
- iscroll_onpullup
- iscroll_onpulldownreset
- iscroll_onpulldownpulled
- iscroll_onpulldownloading
- iscroll_onpullupreset
- iscroll_onpulluppulled
- iscroll_onpulluploading
The event callbacks takes two arguments :
onPullDown(event: Event, data: Dynamic):Void |
The event argument is a basic JQuery Event.
The data argument has only one member : iscrollview, that is the reference to the iscrollview object that made the callback.
And after that, if you want to hide the top or bottom part, just refresh the componant :
data.iscrollview.refresh(); |
Customization
You can also custom the pull label text. All these options has default values, but you can custom them all :
- pullDownResetText (default: “Pull down to refresh…”)
- pullDownPulledText (default: “Release to refresh…”)
- pullDownLoadingText (default: “Loading…”)
- pullUpResetText (default: “Pull up to refresh…”)
- pullUpPulledText (default: “Release to refresh…”)
- pullUpLoadingText (default: “Loading…”)
If you want to change those values from the html, just set the correct attribute :
<span class="iscroll-pull-label" data-iscroll-loading-text="Custom loading text" data-iscroll-pulled-text="Custom pulled text">Custom reset text</span> |
For more informations, here is the place you want to go.
A quick start with nape and tilelayer
0Recently, I started a mobile game with NME, and I wanted to give a try to nape. Since I’ve seen the NME’s runnermark, I’ve wanted to try the tilelayer library too. So why not dot it at the same time !
Overall view
Nape
This month was annonced the 2.0 version of nape. Nape is an open-source Haxe/AS3 physics engine that lets you do cross platform applications. It’s fast and powerful (actually I prefer nape over box2d, it’s much easier to use, and really fast). See by yourself : http://napephys.com/samples.html.
Just download it through haxelib :
haxelib install nape |
Tilelayer
To quote the github description :
A lightweight and very optimized wrapper over NME’s powerful but lowlevel ‘drawTiles’ which offers the best rendering performance (ie. batching) on native platforms.
To install the haxelib version :
haxelib install tilelayer |
AGE – How to support physic engines
0In the previous post, we have seen how to use the Box2D support into the AGE engine. Now I just want to show you how simple it is to add a new framework/engine support.
For example, we are going to add the Nape support.
For those of you who don’t know, Nape is a Haxe/AS3 physics engine. Since Nape is really close to Box2D, it will be simple to understand how box2d has been added to AGE.
The behavior
Since AGE is based on a behaviors system, we are just going to create a new behavior, that we will call NapeMovementBehavior :
class NapeMovementBehavior implements IBehavior { private var _entity : BasicEntity; public var enabled(default, null) : Bool; public function update():Void {} public function enable() { enabled = true; } public function disable() { enabled = false; } public function destroy():Void {} } |
Now we are going to initialize the data needed by Nape for the behavior’s entity :
private var _body : Body; public static var world : Space; public function new(pEntity: BasicEntity, pDynamic:Bool) { if(world == null) world = new Space( new Vec2(0, 500) ); _body = new Body( (pDynamic ? BodyType.DYNAMIC : BodyType.STATIC), new Vec2(pEntity.x + pEntity.halfWidth, pEntity.y + pEntity.halfHeight) ); var block:Polygon = new Polygon(Polygon.box(pEntity.width,pEntity.height)); _body.shapes.add(block); _body.align(); _body.space = world; _entity = pEntity; } |
If you need more information on how Nape is working, go check the documentation.
So for now, we have a basic entity initialized for working into Nape.
(more…)
AGE – Box2D support
1Since Box2D is one of the most used physics engine, I’ve started to implement it into the AGE game engine.
I’ve used the box2d version from haxelib, so don’t forget to add the following to your nmml file :
<haxelib name="box2d"></haxelib> |
I’ve implemented it with the behaviors system. So now we have a Box2dEntity that has a special Behavior (Box2dMovementBehavior) which initialize and update all the Box2D stuff.
For example, to define an entity :
import com.revolugame.age.display.Box2dEntity; class Block extends Box2dEntity { public function new (pX: Int, pY: Int) { super(pX, pY); makeGraphic(32, 32, 0xFF000000); initBox2dStuff(30, true, 0, 0, 0); // ^ friction // ^ restitution // ^ density // ^ if the entity is dynamic // ^ conversion meters to pixels } } |
add(new Block(10, 50)); |
And that’s it !
The Box2D support works with Flash and C++ but needs some optimization for now.
(more…)
AGE – QuadTree implementation
3What is the QuadTree ?
If we look at the wikipedia page, we can find a small explanation (it’s the best one I have found so far) :
A quadtree is a tree data structure in which each internal node has exactly four children. Quadtrees are most often used to partition a two dimensional space by recursively subdividing it into four quadrants or regions.
Why would I add it ?
The first approach to detect collisions between entities was to check for each entity if it collided with one of the others entities in the world. So you can use this method for a really small game, because the number of tests is not that big. But if you have, for example, a game with 100 entities moving around the screen, which can collide with each other, the number of tests between entities will be 100×100 !! And at least half (probably more) of them are not necessary.
The Quadtree allows you to eliminate those unnecessary checks.
How does it work ?
Each time an entity is added to the stage, we just have to look into the tree and find where to put it. A node is simply a rectangular zone with entities and other nodes in it.
So basically, any node will be divided in 4 nodes if more than n entities are completely contained within the node. For AGE, I have decided to use n = 2.
Here is a more concrete example :
Now, our tree has been set. Before checking for collisions, we have to query the tree to determine which entities are worth testing for a rectangular zone (the rectangular zone can correspond to the theoretical position of an entity, to know if we can move it or not). So, the quadtree is going to return each entity contained in a node that have an intersection with our request zone (we have to return entities that are not entirely in a sub node too).
(more…)
Appliquer un tileset sur une tilemap
0Maintenant que nous avons vu comment avoir un monde généré aléatoirement, et pouvant servir de donjon, voyons maintenant comment appliquer un tileset sur cette même map.
Nous avons besoin de déterminer l’état de chaque cellule en fonction de l’état des quatre cellules avoisinantes (on ne prendra pas compte des diagonales).
Plutôt que partir sur des conditions relativement énorme vu le nombre de cas à traiter, nous allons nous baser sur le même principe que pour les nombres binaires, car de la même manière nous devons représenter une combinaison de 4 valeurs dans un état 1 ou 0.
Un peu de théorie
Pour essayer de mieux comprendre, voici l’énumération des premiers nombres, et ce que ça veut dire pour nous.
- Décimal – Binaire (Explication)
- 0 – 0
- 1 – 1 (2⁰)
- 2 – 10 (2¹)
- 3 – 11 (2¹ + 2⁰)
- 4 – 100 (2²)
- 5 – 101 (2² + 2⁰)
- 6 – 110 (2² + 2¹)
- 7 – 111 (2² + 2¹ + 2⁰)
- 8 – 1000 (2³)
- …
Ok… mais comment je détermine la valeur de mes cellules ?
En pratique nous devons donc regarder les cellules environnantes et déterminer la valeur de chaque cellule en fonction des autres.
Tout d’abord le schéma correspondant aux valeurs de chaque cellule voisine :
Une case pleine sur la gauche vaut 8, une case pleine en dessous 4, un case pleine au dessus 1, et une case à droite 2.
Et voici un exemple avec les valeurs pour chaque cellule pleine :
Chaque valeur ainsi obtenue permet d’avoir la position de la tile dans la tileset :
Génération aléatoire d’un donjon
1Dans le post Génération aléatoire d’un terrain, nous avons vu comment générer un terrain grâce à la méthode des Automates Cellulaires.
Dans ce post-ci, nous allons maintenant voir comment générer des donjons, c’est-à-dire avoir la possibilité de se déplacer sur toutes les zones de la carte, sans avoir de murs bloquant le déplacement.
La méthode reste relativement la même, cependant nous allons devoir traiter plusieurs cas supplémentaires.
Le plus gros souci de nos cartes pour un donjon correspond aux trop grosses zones vides. Pour les éliminer, nous allons simplement ajouter une condition supplémentaire à la transformation : si une cellule est entourée de 0 mur dans un rayon de 1, nous passons la cellule en type mur.
for(p in levelMap) if( R1(p) >= 5 || R2(p) <= 1) p = 1; else p = 0; |
Où Rn(p) est le nombre de voisin de type mur à une distance n de la cellule p. La fonction comptabilisant le nombre de voisins compte forcément la case en cours de test.
Voici ce que nous pouvons obtenir en 5 passes :
Comme on peut le constater, nous avons presque toutes les zones accessibles, et aucune grosse zone vide, mais il nous faut maintenant traiter le cas des blocs seuls, isolés un peu partout sur le terrain.
Pour continuer à nettoyer ça, nous allons rajouter des passages supplémentaires, mais avec des conditions différentes :
for(i in 0...3) for(p in levelMap) if( R1(p) >= 5 || R2(p) <= 1 ) p = 1; else p = 0; for(i in 0...2) for(p in levelMap) if( R1(p) >= 5 ) p = 1; else p = 0; |
Ce qui va maintenant nous permettre d’obtenir, par exemple :
Et pour finaliser notre donjon, nous pouvons ajouter les bordures.
Voici un exemple de rendu final avec un ratio de 0.45, suivi de 5 itérations 1, et 3 itérations 2 :
HxSpriter released
0HxSpriter is the Haxe implementation of the Spriter application and file format.
It’s a port a the SpriterAS3 lib, but working with NME. It basically lets you use Spriter with your games or applications.
First of all, what’s Spriter?
Spriter is a powerful animation tool for creating highly detailed 2d real-time game characters and effects in an intuitive, visual editor. The characters are saved to a format that allows game engines to produce higher quality visuals, while also using less video ram, and requiring less disk space per frame than traditional 2d sprite animation.
Spriter also provides several game specific features like collision boxes, and sound effect triggering, and saves to an open format that will be useable across many different game engines and platforms.
Spriter is currently in an usable beta state, but it’s really subject to changes, so the various implementations might stop working from a version to another, and they will need constant updating. The file format may also get incompatible across future versions, and the application may cause some crashes. For these reasons, Spriter is not production ready, but you can test it and play with it if you want.
How to use it ?
To use it, just install it from haxelib :
haxelib install HxSpriter |
In your NME file, you have to define a sprites directory (just rename the directory where you have all your Spriter’s animations).
<assets path="path/to/the/sprites/directory" rename="sprites" /> |
Now, if you want to use the library :
var spriter : BitmapSpriter = new BitmapSpriter('BetaFormatHero.SCML', 100, 300); spriter.playAnimation('idle_healthy'); addChild(spriter); |
Or with the Flixel port :
var spriter : FlxSpriter = new FlxSpriter('BetaFormatHero.SCML', 100, 300); spriter.playAnimation('idle_healthy'); add(spriter); |
Or with HaxePunk :
var spriter : HxpSpriter = new HxpSpriter('BetaFormatHero.SCML', 100, 300); spriter.playAnimation('idle_healthy'); addGraphic( spriter ); |
You can also checkout the repository : https://github.com/po8rewq/hxSpriter.
Génération aléatoire d’un terrain : Cellular Automaton
1Cette méthode est utilisée dans beaucoup de domaines comme par exemple les maths, la physique…
Elle consiste à avoir une grille contenant des cellules, chacune ayant un état (dans notre cas eau/terre).
Pour chaque cellule, on regarde l’état des cellules voisines pour déterminer son nouvel état. Si une cellule est entourée d’au moins 5 cellules de type terre, alors la cellule est transformée en cellule terre, sinon on la passe en cellule de type eau.
Voici un exemple en 8 passes :
Pour plus de renseignements sur cette méthode : Cellular Automaton (ou Automate Cellulaire en français).
Il y a deux façons de procéder lors du traitement des données :
- Pour chaque cellule, faire le traitement et modifier directement les données du tableau (et donc prendre le nouvel état en considération lors du traitement de la cellule suivante)
- On traite les données à un instant t.
C’est cette deuxième solution que nous allons utiliser.
Sauvegarder une liste d’entiers dans un shared object
0Voici une petite astuce qui peut vous simplifier la vie. Dans un grand nombre de jeux, nous avons besoin de stocker la liste des niveaux terminés par le joueur, et de pouvoir y accéder rapidement. La méthode la plus simple est de stocker cette donnée dans un SharedObject que nous retrouverons à chaque lancement de session.
Sauvegarde des données
Pour stocker une liste d’entiers dans un SharedObject sous la forme d’un entier seul, il faut sauvegarder la somme des puissances de 2 des valeurs souhaitées.
var mySo:SharedObject = SharedObject.getLocal("myApplication"); var dataToSave : Array = [2, 5, 4]; var somme : int = 0; for each(var data : int in dataToSave) { somme += Math.pow(2, data); } mySo.data.savedValue = somme; |
Récupération des données
Et pour récupérer les données :
var intValue : int = mySo.data.savedValue; var currentIndex : int; // identifiant du niveau à tester if( ( Math.pow(2, currentIndex) & intValue) > 0 ) { // L'entier est bien présent dans la liste } |








