Showing posts with label app engine. Show all posts
Showing posts with label app engine. Show all posts

Thursday, July 4, 2013

Cross Platform Game Development with PlayN - Concept


The first game I developed was very simple and used the LibGDX framework, it was good experience but I wanted to create a game that was more complex and allowed me to build onto a story.  At the time LibGDX only supported Android & Java.

While searching for possible frameworks to use, I came across PlayN which offered Android, iOS, HTML5, Java & Flash.  Not to mention the fact that is was developed by people at +Google and used by Rovio for Angry Bird Chrome.

I love 2D physics games and I really wanted to create one. My game concept was born from a really awesome movie which included a cast of legendary actors.  However, I needed to make them fictional characters, so I made them worms and of course their enemy is birds. 

The idea of what types of birds they would be didn't come until much latter.  I live in Newfoundland... and we have lots of seagulls.  This spring they were all around my house, perched on the roof, about 20 of them and relieving themselves quite often!!  For about 2 week, we would awake to the sound of these gulls, squawking on the roof. Ohhh, how I wanted to get rid of them PERMANENTLY!!  However, seagulls are a federal protected species, errrr.  So I couldn't kill them in real life, but I can in the game :)

Now with my concept started, I begin into programming.  There is a lot to discuss so I'm going to create a post for each sections of the game I've programmed, +Box2D , +Google Cloud Platform integration, graphics, ageing particle systems, triple play, licensing, Facebook integration, and platform specific code.

Until next time, I would greatly appreciate a like on Facebook or play on Facebook, seems Facebook doesn't list your game in App Center unless you already have people liking and playing it.

Thursday, January 31, 2013

Google AppEngine Search API

Introduction

In the article Geospatial Queries with Google App Engine I discussed my initial attempts to preform geospatial queries using +Google App Engine.  The described how I arrived at my solution but didn't provide any details on my implementation.

Datastore Entity vs Scored Document

I store all my data in Datastore entities, they are easy to save, fetch and run queries on.  So when I first started to read about the search API and having to create a document for indexing I felt there was a lot of overlay with entities.

I had to build a document with fields I had already saved in an entity, I initially created a document with only the fields I required for searching by location along with keys to my saved entities so I could fetch them.  Each time I added\updated an entity I called my index function to keep my index current with my entities.

IndexSpec indexSpec = IndexSpec.newBuilder().setName("locIndex").build();
Index idx = SearchServiceFactory.getSearchService().getIndex(indexSpec);

Locdoc = Document.newBuilder()                               
   .addField(Field.newBuilder().setName("id").setText(eid))                      
   .addField(Field.newBuilder().setName("parentid").setText(RegId))                           
   .addField(Field.newBuilder().setName("regid").setText(RegId))                            
   .addField(Field.newBuilder().setName("active").setText(Active))                                                      
   .addField(Field.newBuilder().setName("location").setGeoPoint(geoLoc))                
  .build();

idx.put(Locdoc);



Geospatial Index Search

After indexing my entities with the new search api, I used it to search for entities with a specific distance from a geopoint and it worked great. 

  String queryStr = "(active:1) AND 
   distance(location, geopoint(" + lat + ", " + lon + ")) < " + userad;

  Results<ScoredDocument> results = getLocIndex().search(queryStr);

        

Initially, I would get the entity key from the document and fetch the entity using the key.  However, I quickly realized this was a bad idea. I check my dashboard quotes and discovered I was hitting two quotes categories "Datastore Read Operations" and "Search API Calls".



Optimization to minimize quote impact

Since I had to use the Search API to locate data by location, I decided to examine all location based searches in my app and encode into the indexed document all the fields I required to handle a user response.

This resulted in much lower Datastore Read Operations and an increase in the response time.  Remember to limit the amount of data you push into your indexed document because there are limitations. See Search API quote.

Thanks for reading, follow me on G+ at +Tim O'Brien

+Kyght
www.kyght.com
tobrien@kyght.com




Note: The above icon is the property of Google and is only here to provide readers with
a visual recognition of the Google product.




Friday, January 18, 2013

Geospatial Queries with Google App Engine

Introduction

While developing an Android app that uses Google Cloud Messaging and integrates with +Google App Engine, I ran into a common App Engine issue. Geospatial queries using High Replication Data Store.  In my application I connect users via their location, when a user performs an action in the app, users in their selected location receive a message via GCM.

DataStore vs Rational Databases

Coming for the rational database world of Oracle and SQL server, I attempted to execute a query to locate devices inside the users selected area.  I used a bounding box to determine what devices are within a given area.  Pleased with my approach, I constructed my filter and updated to App Engine for execution.


query.setFilter( CompositeFilterOperator.and(
   new FilterPredicate(COFFEERUN_ACTIVE_PROPERTY, Query.FilterOperator.EQUAL, 1),
   CompositeFilterOperator.and( 
         new FilterPredicate(COFFEERUN_LAT_PROPERTY,        
                             Query.FilterOperator.GREATER_THAN, 
                             boundbox[0].getLatitudeInDegrees()),
         new FilterPredicate(COFFEERUN_LAT_PROPERTY, 
                                Query.FilterOperator.LESS_THAN, 
                             boundbox[1].getLatitudeInDegrees())
         ),                       

   CompositeFilterOperator.and( 

         new FilterPredicate(COFFEERUN_LON_PROPERTY,        
                             Query.FilterOperator.GREATER_THAN, 
                             boundbox[0].getLongitudeInDegrees()),
         new FilterPredicate(COFFEERUN_LON_PROPERTY, 
                                Query.FilterOperator.LESS_THAN, 
                             boundbox[1].getLongitudeInDegrees())

   )));                    



BOOM!!! Exception (IllegalArgumentException: Only one inequality filter per query is supported)


What! this can't be right, this type of query executes all the time in Oracle and SQL, lets check the documentation.

Google Developers - App Engine - Datastore Queries
A query can have no more than one not-equal filter, and a query that has one cannot have any other inequality filters.


Research & Development

Ok, that's fine, time to do some research, GeoHashing seems to be the answer and the GeoModel project has an App Engine implementation. However, it's a lot of work to integrate and I still have to read my matches to determine if they are within my search area.  

There must be something in native App Engine to handle this type of query, after all Google does it all the time.  I find out there is a native GeoPt datatype in App Engine, I will try using that first to see if it works. 

I update the code to store GeoPt values for device locations and change my query to use the new GeoPt value, I upload my code to App Engine and give it a try.

GeoPt geoLocG = new GeoPt((float)boundbox[0].getLatitudeInDegrees(),              
                          (float)boundbox[0].getLongitudeInDegrees());

GeoPt geoLocL = new GeoPt((float)boundbox[1].getLatitudeInDegrees(), 
                          (float)boundbox[1].getLongitudeInDegrees());
     
query.setFilter( CompositeFilterOperator.and(
   new FilterPredicate(COFFEERUN_ACTIVE_PROPERTY, Query.FilterOperator.EQUAL, 1),
   CompositeFilterOperator.and( 
         new FilterPredicate(COFFEERUN_GEO_PROPERTY,        
                                Query.FilterOperator.GREATER_THAN, geoLocG),
         new FilterPredicate(COFFEERUN_GEO_PROPERTY, 
                                Query.FilterOperator.LESS_THAN, geoLocL)                            
   )));                    
     
             
Iterable<Entity> entities =   
                    datastore.prepare(query).asIterable(DEFAULT_FETCH_OPTIONS);


Yes it worked, it didn't raise an exception and I get some results in my rather large area query. I move on and go back to working on the Android app.

Then during testing I find that I'm not receive some GCM messages and other devices are getting messages that are outside the visual search area on the map. I then start adding integration with Google Places API and custom POI data from various US cities.  I set my testing environment location for my devices to San Francisco, then it becomes very clear.  I'm getting back entries that are outside my query area.

I take each matching entries geographical location and plot it using +Google Maps , I add my bounding box and quickly see there is an issue.  I guess the lesson learned here is, just because it executes doesn't mean it worked.

Conclusion

So the question is "When searching the datastore by location, you can not use an inequality filter for latitude/longitude. Many older articles suggest using geomodel, however with the newer GeoPt datatype, does datastore correctly handle greater than/least than on GeoPt's or does geomodel still have to be used for location queries?"

Thankfully I recently joined +Google+ , and was able to ask that very question to the +Google Cloud Platform Developers . If you want to view the post directly, click here.

They suggested I use "App Engine Search API (Experimental)", which comes with the following note

Experimental!
Search is an experimental, innovative, and rapidly changing new feature for Google App Engine. Unfortunately, being on the bleeding edge means that we may make backwards-incompatible changes to Search. We will inform the community when this feature is no longer experimental.


I changed all my code to use the Search API and it works awesome.  I double checked all matches using   +Google Maps and it was perfect.

So if your looking to perform location based searches, have a look at +Google App Engine Search API.

Here is a link to the Java Search API reference doc "Search API - Performing Location Based Searches"

Let me know if you have any issues or need more info, you can find me on +Google+  at  +Tim O'Brien


Thanks for reading.

+Tim O'Brien
+Kyght
www.kyght.com
tobrien@kyght.com



Note: The above icon is the property of Google and is only here to provide readers with
a visual recognition of the Google product.