Appstore Blogs

Appstore Blogs

Want the latest?

appstore topics

Recent Posts

Archive

Showing posts tagged with game

April 30, 2014

Jesse Freeman

One Game, Everywhere

Gone are the days where you can make a game and publish it to a single platform and expect to be successful. Like any business that sells consumer products, you need to go where the people are. That means the games you make should run on a multitude of different platforms and accept any number of different input types. There’s also one more catch: your players expect to be able to share their game data across all of these different platforms, especially if they are paying for your game multiple times. With that in mind I have outlined what I call “responsive game design,” which is modeled loosely after some of the core concepts of responsive web design. It’s also a framework that will help you think about enabling your games to scale across multiple platforms.

Applying Responsive Design Concepts To Games

On the web, responsive design is a set of guidelines and best practices that help websites scale from desktop to mobile. Web developers discovered early on that it was too difficult to maintain separate designs for desktop and mobile so this solution allows a site to re-adjust to any resolution based on a set of ideal screen sizes. While responsive design on the web focused solely on adapting a site’s visual design based on common viewports, the notion of responsive game design builds on this concept to include other key aspects you need to consider when making multi-platform games.

Responsive game design can be summed up in the following key requirements:

  1. Game graphics and UI support multiple resolutions
  2. Game mechanics work across multiple types of input
  3. Publish to multiple platforms with the same codebase
  4. Saved data is synced across all platforms

While most of these are already best practice for games in general, the collection of them represent a guideline for game designers moving forward to help reach the broadest audience possible.

1. Scaling Game Visuals Across Different Resolutions

If you come from desktop game development this is not going to be a big shock to you since it’s common practice to support multiple-resolutions and varying computer performance. While mobile development is relatively new in this space, over the past few years, mobile device resolutions have tended to normalize around a few key aspect ratios (3:2, 4:3 & 16:9) allowing the same desktop game concepts to be applied:

  • Build for aspect ratios not fixed resolutions
  • Create simplified, dynamic UI that can adapt to different resolutions
  • Have degradable graphics that can adapt to the power of the device

It’s also important to note that optimizing a game’s graphics goes well beyond just the resolution. Each system has different performance so being able to dynamically scale the game’s visual effects across these different platforms is critical as well. Especially when dealing with high pixel density displays, you could actually end up pushing incredibly high resolutions on devices that can’t fully support them. Also you may need to tone down specific special effects on mobile verses desktop or perform special optimizations when going to TV to account for slower display refresh rates. Make sure that you take into account these limitations and plan accordingly.

2. Supporting A Single Control System Across Different Input Types

A single game can support three types of input (mouse + keyboard, controller and touch) based on the device they are on. While thinking through each of these inputs, game designers should consider how their game will work going from desktop to tablet to phone and TV. Will the controls hold up on a system without physical buttons or should the gameplay be simplified a bit to account for the lowest common denominator?

It’s completely possible to have games work with a single input mechanic but a lot of planning and consideration must go into the overall design of the game. Most devices accept a game controller at this point so while not ideal, players can still plug one in if virtual controls are too frustrating. It’s especially important to take into account that not everyone who plays your games will have access to a controller. The Fire TV ships with a remote by default so if you want to capture the largest audience possible you’ll want to make sure you support the remote out of the box. You can still publish a controller only game but keep in mind that each input limitation you place on your game shrinks your potential audience accordingly.

3. Publishing a single game from the same codebase.

For years, developers had leaned on C++ as a cross platform solution to making games that work across multiple platforms. A successful port could be anything above 50% core reusability. I still know developers who build their own game engines that allow them to manually port from platform to platform but that process can be time consuming and if you are a small indie developer, the additional bug testing time may not possible to maintain across all the devices you want to support. That is why it is critical to find a cross publishing solution you feel comfortable with.

The most popular game engine today for indies is Unity 3D. From there other solutions, which grow in complexity, are Unreal Engine, CryEngine. There also some smaller more specialized game engines like GameMaker Studio. If pre-built game frameworks are not your thing, consider some cross compilers like HaXe, Monkey and CocoonJS. Either way there are many options and each will have some kind of impact on your end result or the platforms you can reach so do your research while designing your game.

4. Saving State Across Devices

What good is having a game that can be played on multiple platforms but the player needs to restart their progress every time? A key component to the responsive game design concept is allowing a single game session to extend across different devices allowing your player to start on one platform and continue on another. Imagine being able to play a Fire TV game at home then continuing your game on the go on any mobile device?

Steam was one of the first game publishing platforms to introduce cloud based game saving and since then more companies have offered similar solutions. The biggest issue is that these services are platform specific. For a developer to support different platforms, they would have to roll their own solution. However, built into our GameCircle API is WhisperSync, which can be used to not only have cross platform leaderboards but also sync game data across different mobile devices.

By adding GameCircle’s WhsperSync to your game, you can leverage this to let your players go from mobile (iOS, Android and FireOS) to the Fire TV for the full 10-foot experience then sync their game data back across all of these devices. While GameCircle doesn’t support PC syncing today, being able to have a consistent saved game mechanism for your mobile and Fire TV builds is a huge advantage for your players and a step in the right direction.

Where Do We Go From Here?

While this is just the foundation for a larger concept in game design, it’s up to you as the game designer to help define and shape the future of what gaming on multiple platforms means to the player. At Amazon we are incredibly focused on the customer and we build tools to help you as the developer serve them better. Over the next few years we will see more and more games that reach across platform walls to enable a gamer to pick the device and play style they want and with the correctly designed game, that player will have the same experience no matter where they choose to play your game.

Resources:

- Jesse Freeman (@jessefreeman)

 

February 06, 2014

Peter Heinrich

If you develop apps or games with Unity, you may already be using Amazon’s GameCircle plug-in for Unity to integrate cross-platform leaderboards, achievements, and game data synchronization.  The plug-in works on iOS, Android, and Fire OS, connecting your app to Amazon’s GameCircle service.  Its leaderboards and achievements encourage friendly competition and replay, while its Whispersync for Games component backs up game data to the cloud, improving the customer experience.  With GameCircle, gamers won’t lose their progress if they reset their device or buy a new one.

If you haven’t used the GameCircle plug-in yet, you can now download it from the Scripting/Integration section of the Unity Asset Store.  Accessible directly from within the Unity development environment, the Unity Asset Store makes it fast and convenient to add editor or game functionality through third-party extensions like the GameCircle plug-in.

 

 

This official GameCircle plug-in is compatible with iOS and Android phones and tablets, as well as Kindle Fire, Kindle Fire HD, and Kindle Fire HDX devices.  Add the plug-in to your project to access GameCircle leaderboards, achievements, and Whispersync for Games.

In addition, the GameCircle plug-in also works with the Unity Social API, which provides a unified interface to social back-ends such as Game Center and Xbox Live.  Set the active social platform to GameCircle and calls to the Unity Social API will pass through to the GameCircle service in the same way:

#if UNITY_IOS || UNITY_ANDROID
Social.Active = GameCircleSocial.Instance;    
#endif

Since Unity’s Social API is designed to be a generic interface that works across many services, it doesn’t support every feature of every back-end.  GameCircle leaderboards and achievements work seamlessly, for example, but Unity’s Social API provides no hooks for game data synchronization.  To use some advanced features of GameCircle, like Whispersync for Games, simply call the API through the normal GameCircle interface.  It’s easy to use the two APIs side-by-side, and the plug-in includes a sample scene to help you get GameCircle and Unity’s Social API up and running together.

Check out the official GameCircle plug-in in the Unity Asset Store.  It’s easier than ever to get started integrating GameCircle’s leaderboards, achievements, and Whispersync for Games in your Unity-based game for most mobile devices.  You can also visit our developer portal for more detailed information about using GameCircle and Unity together, as well as links to help you call other Amazon services from your Unity projects.

 

January 29, 2014

Mike Hines

Last week, I wrote to tell you about the new Dolby SDK that makes it easy for you to optimize the sound on the device to match the different kinds of audio you use in the course of your app. This week, we have some feedback from a developer who has implemented the Dolby Plug-In for their app on Kindle Fire.

Luxurious Animals is a game developer in New York. They wrote the casual game Lux Ahoy!, a netmagazine.com Top-10 game. Before working with Dolby Digital Pro, they didn’t consider audio to be a key component.  However after using the Dolby Plug-in, Luxurious Animals had this to say: “The API created a much richer and more immersive experience, making the game feel more exciting and absorbing.  It really took our game to the next level.”

Overall, Luxurious Animals found the Dolby Plug-in to be easy to work with and required no changes to the overall workflow:

“Adding the Dolby magic to our app was as easy as linking a JAR file with our project and calling Dolby-specific methods from our app. We used the Game audio profile inside the API, which creates a ‘live’ space to best bring out the effect of fast-moving objects in the audio. The API also offers Music, Movie and Voice profile options.  We had Dolby capabilities in the game up and running in less than 15 minutes. The API package comes with a Javadocs and a quick-start guide along with a sample application showing how Dolby APIs should be invoked.

Today, we have a fun casual game that not only has great-looking graphics, but also a rich soundtrack that pulls users in and holds their attention. We are confident these enhancements have increased the overall experience for our customers on the Kindle Fire HD.”

I’m thrilled that Luxurious Animals has been able to improve the customer experience for relatively little effort; it speaks well to the smart API design by the Dolby development team.  

To learn more about the Dolby Digital Plus SDK, please read the previous blog post on the topic here, or get the SDK directly from Dolby here.

 

September 27, 2013

Peter Heinrich

Amid all the hoopla around GameCircle’s expansion to iOS and a major update to Whispersync for Games, you may not have noticed two other powerful features were also released recently. The GameCircle team quietly added support for bulk creation of leaderboards and achievements on the Mobile App Distribution Portal, as well as the ability to internationalize them in up to eight languages besides US English. Both have been popular feature requests.

Internationalization means that GameCircle will display the title and description of your leaderboard or achievement in the language appropriate to your player’s locale, provided they have specified it in their mobile device settings. You can provide translated descriptions in any or all of these languages:

 

You enable these alternative versions by selecting them from the Add a Language dropdown list on the Leaderboard or Achievement view for your game. To view your game’s leaderboards, for example, go to the GameCircle configuration page and follow the View link in Leaderboards column.

 

Adding an additional language is not reversible, but you specify which ones to publish, so there’s no harm done if you change your mind or add the wrong one: simply don’t publish that version of the title and description.

Once you add a language, you will see a new corresponding line item for each leaderboard or achievement, which is independently editable.

Providing alternative versions for each title and description, while straightforward, may become unwieldy when you are translating for a lot of locales, or just have lots of leaderboards or achievements. In fact, as the number of leaderboards and achievements goes up, entering all of the other information required to create them definitely makes manual entry time-consuming.

This is where GameCircle’s new bulk upload facility becomes really handy. Rather than create each achievement individually, for example, you can create a file of comma-separated values (CSV) defining all of your achievements at once. From the list of Achievements for your game, click the Bulk Add Achievements button.

On the page that appears, download a CSV template via the click here link. Open the template and fill in the columns as appropriate, then save it locally. See the Create Multiple Achievements section of Implementing Achievements for more information on each column. You will notice, for example, that there are separate columns for each possible translation of title, locked description, and unlocked description. Icon ids for locked and unlocked versions of the achievement are shared across all languages.

Before you can upload the CSV file defining your achievement (or leaderboard) metadata, however, you must upload the icons it refers to. GameCircle provides an Icon Gallery for this purpose, which allows you to add, delete, and rename icons individually or by dragging and dropping them on a web page. You can view the Icon Gallery for your game from the GameCircle configuration page. See Using the Icon Gallery for more information.

Once the icons have been saved and the CSV file updated to reflect your achievement metadata, you’re ready to upload. Click Choose File and navigate to the file you just edited, and then upload it.

Mobile apps and games distributed through the Amazon Appstore for Android are available in nearly 200 countries worldwide, and now GameCircle allows you to provide title and description translations for several of them. Entering the metadata that defines your achievements and leaderboards also got easier, now that you can upload it as a CSV file. Added in response to developer feedback, these features were designed to complement each other and make working with GameCircle fast and simple.

 

August 28, 2013

Daniel Winner

Today we announced the availability of Free-to-Play store in Germany.. If you have built a PC, Mac or Browser-based game, you may be want to list your game and in-game items on our new Free-to-Play store in Germany. Doing so will get your game in front of millions of potential customers in Germany and Austria.

After you set up your game and in-game items for sale, they will be surfaced in Amazon’s personalization and recommendation widgets. 

Customers can enjoy the convenience of purchasing in-game currencies, starter packs, characters, etc. using their Amazon accounts. For German and Austrian customers, this means they can use their bank accounts (Girokonto) or their credit cards to purchase.

With this announcement, we are releasing our App Commerce SDK, which enables customers to create an account with your game right from Amazon.de. Customers can then send in-game currency or virtual goods directly to their game account.  Included in the App Commerce SDK is our In-App Purchasing API for PC, Mac and Web-based games. This API allows customers to purchase virtual goods from your in-game storefront using their Amazon accounts.

To get your game and in-game items in front of millions of customers in the US, UK, and now Germany and Austria, go to the Free-to-Play store developer page to learn more. You can also contact Amazon at find-more-gamers@amazon.com for more information and to publish your Free-to-Play game on Amazon.

August 13, 2013

Peter Heinrich

Amazon GameCircle and the other game services we offer are designed to make mobile game development easier, but knowing where to start may still be difficult. To offer a bit of guidance, I thought it might be worthwhile to take a small, simple game and walk through the process of extending its functionality, one service at a time. Together we’ll gradually add features over the course of several posts, each one focusing on a specific way Amazon services speed development or reduce code complexity. At the end of the series, we’ll have a working game application that shows these services in action and demonstrates how you might incorporate them into other projects.

As the title implies, this post will kick off the series with a look at GameCircle, which supports leaderboards, achievements, and Whispersync for Games, a powerful mechanism to synchronize local and cloud data. Games have been saving progress and celebrating player success since the beginning, so GameCircle seems like a good place to begin our journey.

Prerequisites

Note that this blog series assumes that you are comfortable developing for Android using Java and Eclipse, and that your development environment is set up and working properly with the Android Developer Tools (ADT). Some Amazon services are available only on Kindle Fire, so that will be our target device throughout the series. You must install the Kindle Fire SDK add-ons in order to use those features. For more information, see the Get Started section of Kindle Fire Development Resources.

Importing the Monster Tag Project

Before we begin, we need a simple game that will serve as the base for our experimentation and improvements. Monster Tag displays a horde of monsters and asks the player to tag them as they bounce around the screen. Every time a monster is tagged, it gets startled and speeds off in another direction. The faster a monster is moving when it’s tagged, the more points are awarded to the player.

To import the Monster Tag project into Eclipse, download and extract the source bundle to a convenient location, then choose File | New | Project… from Eclipse’s main menu. Expand Android and select Android Project from Existing Code, then click Next

Click Browse… to navigate to the temporary location where you extracted the source code, then click OK. Check Copy projects into workspace and click Finish

Once the project has been loaded successfully, you will see it in the Package Explorer:

Launch the application in the debugger for the first time by selecting the MainActivity and choosing Run | Debug As | Android Application from Eclipse’s main menu. You should see a lot of little orange guys flying around, daring to be tagged.

Establishing Trust

We have a basic game application running, but we’re still not ready to integrate GameCircle and use it to track high scores online. The GameCircle service won’t accept connections from just any mobile application—it authenticates requests to ensure they’re coming from trusted apps. Every app or game that wants to access GameCircle (and some other Amazon services) must have an “API key,” which is associated with a security profile for that app. The key tells GameCircle that our app is trustworthy.

To establish a security profile and obtain an API key, we must first let Amazon know about our game, which we do on the Mobile Application Distribution Portal. Sign in or create a developer account there if you don’t already have one. (If you’re creating an account for the first time, you’ll be asked to supply some basic information and agree to some terms and conditions. If you intend to create paid apps, you’ll have to provide some extra info, as well.)

Once you’ve logged in, go to the Apps & Services tab and hover over the Add a New App drop-down, then select Add new Android App. Now we can tell Amazon the details of our game:

Generating a Security Profile

After clicking Save we could add more details, such as pricing, icons, and screenshots, but for now we’ll skip those steps and jump right to creation of a security profile. Follow the Security Profile link that appears under the app title on the next screen, then click the Create a New Security Profile button.

You’ll be asked to name the security profile. Note that you can share security profiles between applications, which we’ll discuss in a later post. For now, we’ll assume only Monster Tag will use this one, so we’ll name it accordingly:

Creating an API Key

Now we have a security profile, but no API key has been associated with it yet. Follow the API Keys link that appears after the profile name, then fill in the required fields and click Generate.

NOTE: What you enter in the signature field, below, will depend on your own development environment; you must supply the MD5 signature of your own debug keystore. You can find information about obtaining this value in the Debug application signature section of Getting Your OAuth Credentials and API Key. Typically this involves using keytool (installed as part of the JDK) from the command line:

keytool -list -v -alias androiddebugkey -keystore /path/to/debug.keystore

You should be asked to supply a password, which is “android” by default (no quotes). Check the output for the MD5 signature, highlighted below:

...

Certificate fingerprints:

         MD5:  D4:81:0C:AA:3D:45:DE:45:59:F2:BE:DE:95:A8:E1:65
         SHA1: A1:DF:DD:0D:89:77:81:24:E0:AF:47:AA:B6:55:B6:14:58:7D:4C:E4
         SHA256: 5:50:7F:6F:43:2C:3E:CD:D6:46:F1:F7:96:F2:ED:DE:E8:DD:3A:53:00
         Signature algorithm name: SHA1withRSA
         Version: 3

Adding an API Key to an Eclipse Project

Generating the API key will result in a long base64-encoded string. This is the magic value we need to include in our project to identify our app as trustworthy.

To add it to the project, create a new file called /assets/api_key.txt and paste in the value. Note that api_key.txt must be located in the /assets subfolder.

Enabling GameCircle Data for a Security Profile

Next, we must indicate that there will be GameCircle data associated with the security profile we just created, and that our Monster Tag game will use it. Go to the GameCircle configuration page, select the security profile we created and click Confirm.

Connect a Security Profile to the App

To connect our game to the correct GameCircle data, go to the My Apps tab of your profile, click the Monster Tag app, then follow the Security Profile link. Click the Monster Tag radio button and confirm the action by selecting Apply Profile on the dialog that appears.

Next Steps

Success! Our app is registered with Amazon, there’s a security profile associated with it, and we generated a corresponding API key and added it to our project. We’re ready to use GameCircle and it’s ready to accept requests from our mobile application.

In the next installment of this series, we’ll use GameCircle’s built-in leaderboard functionality to track high scores and let users compete with each other. Now that we have the app and security bookkeeping out of the way, it will be a cakewalk.

 

August 08, 2013

Peter Heinrich

Mobile app and game developers are no strangers to working in the cloud, which is why Amazon has added a dedicated Mobile and Gaming Track to its AWS re:Invent conference this year. Held November 12-15 in Las Vegas, AWS re:Invent will offer dedicated sessions and a special bootcamp tailored to mobile app and game developers like you. Register early as the conference sold out last year!

Deep dive technical sessions and hands-on labs will teach you how to scale your mobile app or game on the AWS cloud, distribute on Amazon, reach millions, increase user engagement and monetization, and more. You’ll also have the opportunity to meet Amazon teams in person, get one-on-one support, and attend a special reception.

Technical sessions during the main conference will focus on AWS features and services that speed mobile development and increase your audience. You’ll also learn how to get the most from Kindle Fire hardware without sacrificing compatibility on other mobile devices. Developer case studies will explain the tips and tricks they used to successfully monetize their apps and games. Here’s a sample of sessions to be offered:

A pre-conference bootcamp will dive even deeper, with a full day of intensive instruction and live coding with the Amazon APIs, including GameCircle, A/B Testing, In-App Purchasing, and Mobile Ads. Starting with design patterns common to Games-as-a-Service and deployment to AWS, this workshop will move on to the specifics of implementation, publishing on the Amazon Appstore, and how to market your application or game on Amazon.com and Kindle Fire devices.

Join us in Las Vegas this November for the dedicated Mobile and Gaming track at AWS re:Invent 2013.

 

August 01, 2013

Peter Heinrich

Following up on the second in a series of webinars covering Amazon devices, game services, and mobile applications, here’s a list of questions we collected during and after our presentation on Amazon GameCircle, including Achievements, Leaderboards, and Whispersync for Games.

 

Does the developer have access to the GameCircle nickname?

Yes, you can call getLocalPlayerProfile(), which returns a structure containing player id and player alias (same as nickname/username). NULL is returned if the player is in guest mode (they have not logged in). Player id is unique for each player.

When updating Achievement Progress can you decrement it as well or does the GameCircleCient hold onto the latest highest progress value?

Achievement progress is strictly increasing, which means updates must be greater than the current value or they’ll be ignored. Note that you can reset achievement data for draft achievements (those that have not yet been published).

With the update, does GameCircle still support Kindle Fire 1?

Yes. The GameCircle system app must be updated to v1.1_1101110, however. This should have been delivered OTA. On KF2, the GC system app should be v2.5.2500310 or greater.

Can leaderboards/achievements be translated?

Not yet, but localization is in development and will be available in a future release.

Is the same game discovery mechanism on Kindle Fire available on all Android devices as well?

The dedicated Games Tab is built in to the games library on Kindle Fire only. It’s not available on other Android devices.

What is the minimum OS supported?

GameCircle supports API level 10 up to API level 16 on all Android devices.

Is GameCircle available internationally?

Yes, GameCircle works internationally. Players in China are limited to Guest mode for now, due to data storage requirements imposed by the Chinese government, but we will address that in a future release.

Is the old version of GameCircle still supported?

Yes, for legacy games. Games that have been published using GameCircle v1.x will continue to work. If you had a game in development when GameCircle v2.0 was released, you can proceed to publish it using the old version. Since the Mobile App Distribution Portal no longer provides direct support for GameCircle v1.x app whitelisting, however, you must contact us to add or update package name/signature pairs. See the Whitelisting Notice on the GameCircle configuration page for more information.

What happened to the FileSync and BlobSync from Whispersync?

We greatly simplified the Whispersync interface to make it easier to integrate and expand auto-resolution of data conflicts. As a result, we dropped support for the blob and multifile sync options. They were complicated to integrate and forced the developer to manually reconcile data on occasion (or to ask the customer to do so). The new Whispersync requires significantly less integration overhead and provides a better customer experience in most cases.

Can I migrate old Whispersync data to the new format?

Yes, there are two methods on the WhispersyncClient that can help in the migration process. migrateVersion1GameData() and unpackVersion1MultiFileGameData() will download and unpack data stored using the previous version, respectively. They’re only meant to be used by games that integrated Whispersync prior to July 1, 2013. See the Javadoc for more info.

Is there any way to integrate game circle in Air apps?

Amazon provided an Adobe Native Extension (ANE) for GameCircle v1.x, but none is yet available for the new version. We are actively researching an upgrade to the existing ANE, but don’t have an official timeline. Check back here or follow @peterdotgames for updates on the availability of a new ANE. In the meantime, you can continue to the existing extension with GameCircle v1.x for games currently in development.

Where can I learn more about Unity plugin for game circle?

Check out the Amazon Unity Plug-Ins page on the Amazon Mobile App Distribution Portal.

Do users need to login with Amazon account username and password to use the game services?

No, GameCircle now supports a Guest Mode for users who don’t want to log in to an Amazon account. In this case, data will not be synchronized to the cloud or across devices.

Is there a good game to play to check out the features?

There are many great games that include GameCircle features, including well-known blockbusters and high-quality indies. In the Amazon Appstore, look for the GameCircle badge to quickly identify games that use Achievements, Leaderboards, or Whispersync for Games.

 

Don’t miss out next webinar event: How to Integrate Amazon Mobile Ads and Lift Your App Revenues 
on August 15th, 2013 @ 10:00 AM.

Pre-register here!

July 23, 2013

Peter Heinrich

Save game data in the cloud to protect your customers’ progress and support play from multiple devices

In just a few short years, the explosion in popularity of smart phones and tablets has transformed gaming, as touch controls, geolocation, and micropayments enter the mainstream. Online storage is also becoming more common, as developers adjust to a major challenge of mobile devices: physical durability. Keeping your data in the cloud starts to look mighty attractive compared to keeping it on a device that’s easily misplaced, damaged, or stolen.

Blob storage is a common way to save data online (game data is simply written to the cloud as one big chunk). If two devices update the same data, though, one of the updates must be ignored or overwrite the other. You have to decide which update to keep (based on a timestamp or version number, perhaps), or maybe prompt the user to choose between them. Either way, data is lost.

Because of the overhead involved, many developers don’t even bother with this naïve approach. This is a huge disservice to the player, whose game progress is completely lost if anything happens to his or her mobile device. Whispersync for Games saves game data for you, and works across all Android devices (including Kindle Fire).

Mergeable and Non-mergeable Data

Whispersync was designed to prevent data loss, make developer or player intervention unnecessary when resolving conflicts, and be dead-simple to integrate and use. It doesn’t distinguish between online and local storage, so the programmer doesn’t have to handle separate cases for saving to disk and cloud. It does this by manipulating only mergeable data.

Game data is mergeable if a simple rule can be defined to resolve conflicting values. For example, the rule associated with the best completion time might be, “Take whichever value is smallest.” To keep track of a player’s best score, we might use, “Take whichever value is highest.” In some cases, the most recent value may be the most important, so the appropriate rule would be, “Take whichever value is newest.” These rules apply at a granular level; Whispersync doesn’t treat game data as one big chunk.

Not all game data can be resolved using simple rules, though, in which case we call it non-mergeable. The current state of a chess board, for example, requires a complex tree structure to describe it. Reconciling two versions of the board is more complicated than just choosing the “lowest” or “highest” one.

Describing Game Data Using Syncable Types

Fortunately, a lot of game data is naturally mergeable or can be adjusted to be so. Whispersync offers many different syncable types with several built-in rules to resolve conflicts. They can be used to model simple and complex game data.

  • SyncableNumber – A number that is the lowest, highest, or most recent.
  • SyncableString – A string that is the most recent.
  • SyncableAccumulatingNumber – A number that can be incremented and decremented.
  • SyncableNumberList – A list of numbers in ascending, descending, or latest order.
  • SyncableStringList – A list of strings ordered by most recent.
  • SyncableStringSet – A set of strings.
  • GameDataMap – A nested map, allowing hierarchical data.

A global GameDataMap object represents the root storage for your game, storing named values of the types above. Setting a value that doesn’t exist will create it on the fly. The accessor used to retrieve a value determines the conflict resolution strategy that will be associated with it.

  public static final String SKILLS = "skills";
  public static final String TOTAL_TIME = "totalTime";

  public static final String LEVEL_MAP = "levelMap";

  public static final int NUM_LEVELS = 5;
  public static final int MAX_ITEMS = 3;

  public static final String SCORE = "score";
  public static final String STARS = "stars";
  public static final String BEST_SCORES = "bestScores";
  public static final String BEST_TIMES = "bestTimes";

  GameDataMap gameDataMap;

  public void initGameData() {
    gameDataMap = AmazonGamesClient.getWhispersyncClient().getGameData();

    // These will be independent of level.
    gameDataMap.getStringSet(SKILLS);
    gameDataMap.getAccumulatingNumber(TOTAL_TIME);

    // Use nested maps to establish some per-level values.
    for (int i=0; i < NUM_LEVELS; i++) {
      GameDataMap levelMap = gameDataMap.getMap(LEVEL_MAP + i);

      // Each level will have its own copy of these values.
      levelMap.getLatestNumber(SCORE);
      levelMap.getHighestNumber(STARS);
      levelMap.getHighNumberList(BEST_SCORES).setMaxSize(MAX_ITEMS);
      levelMap.getLowNumberList(BEST_TIMES).setMaxSize(MAX_ITEMS);
    }
  }

In the example above, we use initGameData() to establish the structure of the data we’ll synchronize, even though we don’t actually set any values. (It can be helpful to define the data layout in one place like this, even if it’s not strictly required.) The code effectively says,

  • There will be a global set of strings called SKILLS. It will track every string added to it (strings may not be removed).
  • There will be a global running total of time in the game called TOTAL_TIME. It will accumulate deltas submitted from all devices used by a single player.
  • There will be NUM_LEVELS nested maps, each of which will have its own set of values:
    • SCORE will always reflect the last score submitted for that level.
    • STARS will always reflect the maximum stars attained for that level.
    • BEST_SCORES will always list the MAX_ITEMS highest scores for that level.
    • BEST_TIMES will always list the MAX_ITEMS fastest times for that level.

Updating and Retrieving Game Data

Whispersync abstracts all game data persistence, so we can update or retrieve values using simple getters and setters. We don’t have to worry about managing a network connection, saving to disk or the cloud, or reconciling local and online versions of variables we have in memory. When we add to the running total of time played, for example, Whispersync automatically saves the delta to disk and updates the cloud if connected. If the player’s device is currently offline, the update will be queued and delivered later.

  public void updateTotalTime(int timePlayed) {
    SyncableAccumulatingNumber totalTime = gameDataMap.getAccumulatingNumber(TOTAL_TIME);

    // Add the time played to the running total.
    totalTime.increment(timePlayed);

    // Output the new total to the console.
    System.out.println("Total Time Played = " + totalTime.asInt());
  }

Likewise, we can record skills as the player masters them and easily iterate over the set to display the ones learned so far:

  public void learnSkill(String skill) {
    SyncableStringSet skillSet = gameDataMap.getStringSet(SKILLS);

    // Add the new skill to the player's repertoire. Note that this list

    // can only expand; strings cannot be removed.
    skillSet.add(skill);

    // Output all skills to the console.
    for (SyncableStringElement s : skillSet.getValues()) {
      System.out.println("Skill = " + s.getValue());
    }
  }

Updating numbers and number lists is just as straightforward, so persisting all of the player’s progress at the completion of a level can be done in just a few lines:

  public void finishLevel(int level, int score, int stars, int time) {
    GameDataMap levelMap = gameDataMap.getMap(LEVEL_MAP + level);

    // Save the score for this level. Newer values will always overwrite
    // previous scores.

    levelMap.getLatestNumber(SCORE).set(score);

    // Try to set the new maximum stars attained on this level. If the
    // value is less than the current maximum, this call does nothing.

    levelMap.getHighestNumber(STARS).set(stars);

    // Try to add this score to the list of all-time bests. If it's not
    // high enough, this update will be ignored.

    levelMap.getHighNumberList(BEST_SCORES).add(score);

    // Try to add this completion time to the list of all-time bests. If
    // it's not low enough, this update will be ignored.

    levelMap.getLowNumberList(BEST_TIMES).add(time);
    updateTotalTime(time);
  }

The accessors on GameDataMap and Whispersync’s syncable types make it easy to manipulate game data and define how conflicts should be resolved.

Think Mergeable!

Whispersync for Games automatically resolves conflicts for data it can merge, which makes it worthwhile to describe game data using syncable types when possible. Since Whispersync supports high, low, and most recent numbers and number lists; running totals; latest strings and string lists; sets of strings; and nested maps supporting hierarchical structures, a wide range of game data can be modeled.

Thinking about your game data in mergeable terms lets you push a lot of overhead out of your code. Let Whispersync handle the heavy lifting. For more information on integrating Whispersync into your game, see the online documentation

 

June 30, 2013

Peter Heinrich

We just released a major update to Amazon GameCircle, our free game service providing achievements, leaderboards, and Whispersync for Games. Games on all Android devices (including Kindle Fire, of course) can now integrate GameCircle, which is easy because we support Java, JNI, and Unity3D. Whether you submit your game to Amazon or Google, customers will benefit from the GameCircle experience. In addition, Whispersync has been dramatically improved, becoming the first and only cloud-save service to:

1) Automatically resolve data conflicts between mobile devices and the cloud,

2) Queue updates to support offline operation, and

3) Offer a simple interface that can be integrated in minutes.

The result: Your customers’ game data will automatically sync across devices—even if they play your game while temporarily offline—and you can concentrate on using the data instead of persisting it. You’re not locked in, though; you retain ownership and can always get a copy of the data you store.

We also give you flexibility when it comes to GameCircle display options, with no intrusive splash screen and configurable notification toasts. You’re in control and choose where they appear.

I’ll provide more technical details about these enhancements in future posts, but for now, let’s take a closer look Whispersync and explore its powerful new features and simplified interface.

Whispersync for Games

Whispersync does the heavy lifting when it comes to synchronizing local data to and from the cloud. It handles the tricky scenarios that you would normally have to deal with yourself, like conflicting updates from multiple devices or sync requests from a device that’s temporarily offline. You can also stop worrying about scalability; behind the curtain, Whispersync (and all of GameCircle) is powered by Amazon Web Services like S3 and DynamoDB.

Using Whispersync is easy through an API that has been completely redesigned, providing an interface similar to SharedPreferences. Saving game data to the cloud and synchronizing it between devices is as easy as retrieving a variable from a map and using (or changing) its value:

    // Get the global game data map for the current player.
    GameDataMap gameDataMap = AmazonGamesClient.getWhispersyncClient().getGameData();

    // Look up the object representing the player’s skill rating.
    // If none exists, one will be created.

    SyncableNumber skillRating = gameDataMap.getHighestNumber("skillRating");
    System.out.println("skillRating = " + skillRating.asLong());

    . . .

    // Update the value. As long as this device is online (or as soon as
    // it is), local and cloud storage will be synced.

    skillRating.set(MAX_SKILLRATING);

Whispersync maintains a singleton instance of GameDataMap that acts as the root of your game data. It can track numbers, strings, simple lists, and other maps, and gives you complete freedom in how you represent your game data using these basic syncable types. You add new variables simply by retrieving them by name; if they don’t exist, they’ll be created on the fly and synchronized from that point on.

How Whispersync applies updates and resolves conflicts depends on the way you access each syncable variable. For example, suppose you want to retrieve the current user’s best (highest) level across all devices:

    GameDataMap gameDataMap = AmazonGamesClient.getWhispersyncClient().getGameData();
    SyncableNumber bestLevel = gameDataMap.getHighestNumber( "bestLevel" );
    System.out.println( "bestLevel = "  + bestLevel.asLong());

In this case, because “bestLevel” is retrieved as a highest number, it will always reflect the maximum value ever assigned to it, from anywhere, on any device.

String values can also be synced. You could easily set the name of the latest power-up collected:

    gameDataMap.getLatestString( "lastPowerUp" ).set("Super Boingo"); 

The syncable string associated with “lastPowerUp” will always reflect the value most recently assigned to it.

The online documentation and Javadoc included with the SDK have more information on the syncable types Whispersync supports, as well as the ways in which each may be accessed.

Practical Applications

Let me provide a few more examples to illustrate just how straightforward synchronization can be.

Recording Star Count for Several Levels

A common pattern in many games is to show stars and unlock status for each level on a level selection screen. Here’s an example of using Whispersync to track individual star values for multiple levels:

  SyncableNumber[] getLevelStars() {
     GameDataMap gameDataMap = AmazonGamesClient.getWhispersyncClient().getGameData();
     SyncableNumber[] stars = new SyncableNumber[NUM_LEVELS];

     // Get the star counts for all levels.
    
for (int i = 0; i < stars.length; i++) {
        stars[i] = gameDataMap.getHighestNumber("levelStars" + i);
     }

     return stars;
  }

The first time the score values are accessed (from anywhere), Whispersync will create entries for them in the cloud, so there’s no need to declare them ahead of time.

Accumulating a Running Total

Some progress, like coins collected or time played, represents a running total that is always updated using a delta amount. Instead of setting the value directly, you just submit the amount by which it should change. Whispersync automatically adds or subtracts this value to update the current total. For example:

 void addTimePlayedToTotal(long timePlayed) {
    GameDataMap gameDataMap = AmazonGamesClient.getWhispersyncClient().getGameData();
    SyncableAccumulatingNumber totalTime =        gameDataMap.getAccumulatingNumber("totalTime");

    // This object may be incremented/decremented with long, double, and
    // BigDecimal values.

    totalTime.increment(timePlayed);
    System.out.println("Total time played: " + totalTime.asLong());
 }

Keeping a Map of Maps

By embedding a map within a map, you can create a hierarchical data structure. If your game has multiple worlds, for example, you might keep a separate GameDataMap for each one. Each of these might contain additional maps—say, one for each level.

 GameDataMap getWorldData(String name) {
    GameDataMap gameDataMap = AmazonGamesClient.getWhispersyncClient().getGameData();

    // Get all the string keys associated with top-level GameDataMap objects.
    Set<String> worldNames = gameDataMap.getMapKeys();

    // Look for a match among the maps.
    for (String currentName : worldNames) {
       if (currentName.equals(name)) {
          // A map exists for the name specified.
          return gameDataMap.getMap(currentName);
       }
    }

    // No match found. Don't create one.
    return null;
 }

Maintaining a List of Numbers

A racing game might save a player’s top three best times using a syncable number list. In this case, you could create a list for low numbers—they decrease as times improve—but you could easily choose to retain a collection of the highest or most recent values in other situations.

 // We'll initialize this once the application has launched.
 AmazonGames agsGameClient;
 GameDataMap agsGameData;
 SyncableNumberList agsBestTimes;

 // Create a callback to handle initialization result codes.
 AmazonGamesCallback agsGameCallback = new AmazonGamesCallback() {
    @Override
    public void onServiceReady(AmazonGamesClient client) {
       agsGameClient = client;
       agsGameData = AmazonGamesClient.getWhispersyncClient().getGameData();

       // Establish how many slots will be allocated and preserved.
       agsBestTimes = agsGameData.getLowNumberList("bestTimes");
       agsBestTimes.setMaxSize(3);
    }

    . . .
 };

  void finishLap(double time) {
   // Every time a lap is completed, try to add the lap time
   // to our list of best times. Only the lowest three will
   // ever be preserved.

   agsBestTimes.add(time);
 }

Every time the player finishes a lap, finishLap() would be called to update the number list. The value specified will be discarded unless it is lower than one of the current entries.

More to Come

The GameCircle improvements released in the latest update deserve more attention than the brief overview I’ve given here, so I’ll add details in the coming weeks. Look for articles dedicated to JNI; advanced API features; and using GameCircle with frameworks such as Unity3D, Cocos2d-x, and Marmalade. I’ll also dive deeper into Whispersync, discussing the difference between mergeable and non-mergeable data (and why it’s important), considerations when synchronizing currency across offline devices, and migration from the previous version. Stay tuned!

In the meantime, check out the new GameCircle release and give it a whirl. You’ll benefit whether you use the simplified Whispersync API and its expanded functionality, create a universal build to run on Kindle Fire and Android, or take advantage of the other features included with this update.

June 05, 2013

Peter Heinrich

Game development is an art, like any other. It can be personally rewarding, and like other forms of artistic expression, great games can come from anywhere. Powerhouse game studios don’t hold a monopoly on inventiveness or creativity, and some of the best games of all time were created on a shoestring by two or three people with a shared vision.

It’s hard to get noticed, though. If you’re an indie game developer, it’s usually a headache to get your game in front of people, both gamers and reviewers. Amazon recognizes this. As part of our commitment to independently developed games, Amazon is launching the Indie Games Store, a new category on Amazon in the Digital Video Games Store, designed specifically to address this problem.

The Indie Games Store is a dedicated storefront designed to specifically help indie game developers with promoting their PC, Mac, and browser-based games while helping gamers discover a large and growing selection of innovative indie games.

The dedicated indie-specific storefront offers indie developers several programs to increase discoverability and promote their PC, Mac, and browser-based games while helping customers discover a large and growing selection of innovative indie games including “Don’t Starve” by Klei Entertainment, “FTL: Faster than Light” by Subset Games, and “The Bridge” by The Quantum Astrophysicists Guild.

To celebrate the launch, we’ll also be offering features and promotions starting today to encourage customers to engage with the indie game scene:

  • Indie Spotlight – The Indie Spotlight puts the focus on developers with Q&A and featured bios to give customers a glimpse of each developer’s style and personality. We’ll feature a different indie developer every week starting today with Gaijin Games.
  • Indie Bundles – Starting today until July 23rd, gamers can get great deals on Indie Bundles and increase their collection. These bundles are made up of 5, 6, or 10 games each, and will cost $9.99, which is a discount of up to 90% off if purchased separately.
  • Gift with Purchase – Starting today until July 17th, customers who purchase any indie title from the Indie Games Store, will receive codes to redeem 3 pre-selected titles for free. The games change daily and each purchase entitles customers to 3 free games, so customers are encouraged to check often.
  • Indie Gamer’s Choice– To help connect gamers and developers, we're introducing the Indie Gamer’s Choice program, where gamers can get involved. The Indie Gamer’s Choice positions two indie games head-to-head and allows players to vote on their favorite title to become the Indie Gamer’s Choice, which is featured in the store.

This is a great time for you to check out the Indie Games Store and participate in prominent merchandising on the new storefront. If you are interested in selling your games on the Indie Games Store, contact Amazon Digital Video Games at find-more-gamers@amazon.com.

 

February 20, 2013

Amazon Mobile App Distribution Program

In a recent study of more than 500 games that utilize in-app purchasing on Amazon, we found that mobile games using Amazon GameCircle’s leaderboards and achievements monetized significantly better than other games.

For the three-month period from November 2012 to January 2013, games using GameCircle produced 38 percent higher conversion rates and 33 percent more in-app orders per paying customer than games that didn’t use GameCircle. Conversion was measured by calculating the percentage of app users that made at least one in-app purchase. Combining the impact of both of these variables, GameCircle-enabled games earned 83 percent more average revenue per user (ARPU) than non-GameCircle games. 

 

 

The free-to-play (or freemium)  model, where consumers download and play a game for free, has become one of the most prominent business models in mobile gaming today. However, the biggest challenge for game developers following the freemium model is figuring out how to generate more revenue by converting non-payers into payers and keeping those paying users engaged.

Many of Amazon’s mobile game developers have discovered how GameCircle’s services–Achievements, Leaderboards and Whispersync–have contributed to their success at Amazon. GameCircle lets players connect with other players to compare achievements and compete for higher scores. These social elements get the competitive juices flowing, which may increase a user’s willingness to pay for in-game content, leading to higher conversion rates for developers. “PlayFirst's games on Amazon have performed above and beyond our expectations, and we believe GameCircle has enhanced our ability to connect and engage with Amazon customers, encouraging more play sessions," said Paul Chen, VP of Business Development at PlayFirst.

GameCircle also offers new discovery mechanisms that are an important factor helping drive increased engagement rates. For games that have integrated with GameCircle, players can see their friends, achievements, and leaderboard activity before launching the application, since all of this information is visible right from the user’s game library. Leading games such as Skylanders Cloud PatrolDiner Dash, and Temple Run 2 have already integrated with GameCircle. The image below showcases how a user’s library is populated with GameCircle meta-data.

This added visibility is a powerful engagement tool. A related study that we conducted in January 2013 found that, on average, games using GameCircle over-indexed on the number of player sessions (defined by the number of times users opened the applications on their device) by 32 percent when compared to the average for the entire games category. For freemium games that monetize by selling in-game content, this enhanced level of engagement is critical to expanding customer lifetime values. "We see superior engagement, retention and monetization from players who download our games from Amazon. The GameCircle integration is helping us achieve 40 percent better per user monetization rates compared to non-Amazon players," said Sean Thompson, Vice President of Mobile Deluxe.

For you, GameCircle represents another opportunity to provide gamers with a more seamless and entertaining in-game experience, which can lead to increased engagement and monetization. Please visit the following links if you would like to learn more about the Amazon GameCircle and In-App Purchasing APIs.

January 16, 2013

Amazon Mobile App Distribution Program

With the OpenFeint shutdown on December 14, 2012, many mobile app developers find themselves having to evaluate other social gaming platforms. One such platform that offers tremendous value to developers is Amazon GameCircle for Kindle Fire tablets.

GameCircle makes achievements, leaderboards, and sync APIs accessible, simple, and quick for you to integrate, giving gamers a seamless and entertaining in-game experience.

Additional benefits of GameCircle include:

  • Whispersync for Games: synchronize user game progress to the cloud, across multiple Kindle Fire tablets. Delight your customer by enabling them to save their progress, achievements, leaderboard scores, and all of the content they have unlocked--securely in the cloud.
  • Discovery: when integrated with any GameCircle feature, you have the opportunity to be featured on Amazon, including in the Games Starter Pack on Kindle Fire.
  • Plug-ins: GameCircle comes with plug-ins for many popular engines like Unity, Adobe Air ANE and Cocos2d-x,with more on the way. Even better, they are free. The new plug-ins are available here.

For detailed information on how to migrate from OpenFeint to GameCircle, click here.

December 05, 2012

Amazon Mobile App Distribution Program

Today, we announced a new,free A/B Testing service for developers like you, who distribute their app or game through the Amazon Mobile App Distribution Program. This service was built to help you improve your customer retention and monetization through in-app experimentation. Amazon’s A/B Testing service is easy to integrate, simple to control, and is built on Amazon Web Services. This means you can be up and running in less than a day and trust that the service will scale with your app.

 

When we set out to buil dan A/B Testing service, we met with developers to learn what they needed most.We discovered that it was something very simple--to better understand customer needs and to be able to react to those needs quickly. Our A/B Testing service provides simple to integrate tools that enable you to continually create and run experiments, view how customers are reacting to these experiments, and release new, improved experiences without writing any more code or resubmitting your game or app.

 

The service’s benefits include:

 

Free to Use: our A/B Testing service is free to use for developers distributing their app or game through the Amazon Mobile App Distribution Program.

 

Easy Integration: early partners report that the SDK can be integrated and ready for release in less than a day.

 

Precise Control: set up experiments and monitor results from the familiar Mobile App Distribution Portal.

 

Painless Deployment: server-side logic allows you to quickly iterate tests and deploy new, improved experiences to customers without having to resubmit your APK or write any additional client-side code.

 

Effortless Scaling: built on Amazon Web Services, Amazon’s A/B Testing service lets you focus on building great games and apps instead of architecting scalable back-end services.

 

With Amazon’s A/B Testing service you no longer need to guess when deciding between different customer experiences.You can evaluate which in-game promotion drives better performance, which button design maximizes customer click-through, or which tutorial offers the highest conversion rate. 

 

The Amazon A/B Testing service is currently available in beta. Learn more and get started with A/B Testing here

November 20, 2012

Amazon Mobile App Distribution Program

TashaKim, Public Relations Manager, GAMEVIL, is our guest blogger for this post.

 

GAMEVIL is a leading mobile games publisher and developer headquartered in Seoul, Korea,with branches in Los Angeles, California, and Tokyo, Japan. GAMEVIL has expanded their global presence over the years through an ambitious lineup of internal and third party titles localized in eight different languages. GAMEVIL specializes in mid-hardcore mobile games and prides itself on their strong following of players who enjoy their RPG-based titles.

 

At GAMEVIL,we believe that localization is one of the most important steps during post-game development. Correctly localizing a product not only promotes accessibility toa wide range of players across the world but also establishes global brand awareness. Our games are localized in over eight languages through in-house translators as well as third-party companies. Due to the geographical closeness and cultural similarities, our games are heavily popularized in Asia. Japan, in particular, holds a high percentage of downloads and monetization. We believe this is in part due to the localization of our content into the Japanese language and culture. 

 

Gamevil-1
 

Below are a few guidelines we learned in our experiences localizing to Japanese as well as other Asian countries that may help other developers:

 

Translation is Not Localization

There are countless outsourcing companies overseas that will offer a literal translation of the language, but because so many RPG titles hold a rich and deep storyline,a literal translation would render the story awkward, bland, and lose the interest of the player. At GAMEVIL Japan, we translate the game internally and often outsource to third-party translators as well. Then, we initiate a second round of in-house translations. This portion focuses more on the cultural nuances and idioms that might not have translated seamlessly.

 

Understanding the Culture: The Importance of Physical Presence

We believe that it’s not enough to simply localize into a language through text, but that a full immersion is the best way to understand a culture and what is relevant in the region. The staff members at our Tokyo office are Korean/Japanese who have a sound comprehension of the social and cultural nuances. As similar as East Asian cultures may seem, there are still dynamic differences linguistically between countries that require sensitivity and attention. Once a literal translation is done, GAMEVIL Tokyo will go through a proofread, cross checking the text of the original document and implement any necessary changes. This process usually consists of omitting phrases that are irrelevant and adding text that will vibe well with the Japanese gaming culture.

 

The Importance of Proofreading

One key aspect that remains an extreme priority in our localizing is in the final steps of proofreading. We check each line to make sure that the meanings and expressions held behind each word and phrase flows seamlessly. The last thing that you would want is to make your game seem foreign to native gamers. We will usually have at least three rounds of thorough review before the translation is released to the public.

 

Localize the Entire Experience

One common misconception is that localization simply ends with the text, but localization often applies to the whole game. We cater each game according to regions. For many of our titles, we will implement Global, Asian, and Korean servers to create an experience that is relevant and user friendly. In addition, we take a user’s environment into consideration. For many Japanese users, gameplay will take place during a commute on the subway or bus in addition to heavy gameplay at home. We try to focus on quick loading times to encourage gameplay during short sessions. For our strong RPG and sports titles, we create short side quests such as the Abyss system in ZENONIA® and Exhibition Mode in Baseball Superstars® that can be enjoyed in short sessions. Japanese users are also big gamers and enjoy the anime RPG-style of many of our titles. With an immersive storyline and high-quality visuals combined with a well-polished text, our titles have seen success in terms of downloads and purchases in Japan.

 

Gamevil-2
 

We want to put out a product that seems indigenous to the users as they play the game. Our end goal is to create a game that transcends language and cultural boundaries that can be enjoyed by people regardless of age,gender, and ethnicity.

Want the latest?

appstore topics

Recent Posts

Archive