• Advertisement

Carsten Germer

  • Content count

  • Joined

  • Last visited

Community Reputation

1510 Excellent

About Carsten Germer

  • Rank
  1. Narrative-Gameplay Dissonance

    Good article, Will.   I'm all in favor of decoupling systems within a design, but your suggestion opens up a whole new can of worms:   If your overall design requires or encourages balance you can not really have a "mind-hacking warrior". Simplification: Either very strong or very intelligent, otherwise would be overpowered. Outsourcing the skill set to (swappable) equipment would not remove this completely.   You'll have to design around many possibilities of emerging ludonarrative dissonance. A gentle, intelligent and caring Close-Combat-Type who gets pushed to slay hundreds of dragon-puppies because that's the most (only?) effective way to get somewhere specific for that skill set.   The more one designs around this, the greater the danger of having to "dumb down" encounters and levels in general. I can't remember offhand which one it was, but one of the early Deus Ex games became very easy if you played an all-around Type because the levels/encounters simply had to be doable with all types of combinations (still tons of fun, though).   A more or less inherent connection between mechanics and narrative can be easily violated and can in turn lead to "narrative-gameplay dissonance". There's no "Game Master" in interactive computer games (yet), who judges players decisions, gameplay or story related, and will block the player from acting, based on something like alignment. I've given this a fair amount of thought and prototyped a simple system that does this good enough for games. Using it would require far more design in pre-production and keep in mind, it wouldn't help with the level/encounter problem of having to "dumb down".   I feel that with todays technology one either has to keep possible variations and freedom of choice in restraints or have a big budget to expand and fine tune design and worldbuilding.
  2. Narrative-Gameplay Dissonance

  3. As production of "Pavel Piezo - Trip to the Kite Festival" was recently finished I reviewed the material I collected for the Postmortem and found it too much and too diverse to put in one huge article. So, I identified the topics that can stand very well on their own, which were not limited to this specific game or production, and decided to write three short(er) posts in advance to the Postmortem. Limits of HTML5, Javascript and canvas when developing a "Hidden Object Game for learning languages" "Not so random randomness" in game design and programming Using a "Leitner system" to track a player's exposition to content and mechanics Postmortem: "Pavel Piezo - Trip to the Kite Festival", a game for learning languages Our game "Pavel Piezo - Trip to the Kite Festival" has just been released for the first target platform (find it on iTunes). I decided to write up this postmortem without knowing sales numbers and without being able to share details about marketing on different platforms as "the story so far". When there are interesting numbers to convey after some time, I may write a follow up or update this article for those who are interested in how an "educational game" that employs "peripheral learning" does in the wild these days. The Pavel Piezo series puts a twist to the well known mechanics of Hidden Object Games, namely imparting foreign languages. There are already many good articles (for instance on Gamasutra Learning to Play to Learn and Educational Games Don't Have to Stink!) about educational games; I won't dive into these waters in this postmortem. Initial Idea With one sentence of Ernest Adams in mind, "Admit that games don't teach ...", and a recent study about the effects of peripheral learning the idea came together. The game uses the player's concentration on common objects that are to be found in the game and play a short phrase or sentence in the chosen foreign language containing the word as part of the game's reaction to a player's actions. Simple as that. According to the study it works and a few playtests with prototypes were promising. About the Game (abstracted from Pavels website) "Pavel Piezo: Trip to the Kite Festival" is a hidden object game with six exciting levels. All of the objects that Pavel seeks, finds and uses come with short phrases in the chosen language. A new selection of objects, different hiding places for the hidden objects and a further assortment of spoken phrases for all the actions ensure that the game still remains fun, even if you've visited the kite festival already. The language teaching corresponds to the latest scientific techniques and allows the player to enjoy playing Pavel undisturbed! Six beautiful hand-drawn levels More than 150 objects to find and use Four languages to get to know and learn (level A1) Eight professional voiceover artists Over 7,500 spoken phrases Impressive music, background sounds and effects give the game an added dimension What Went Right Starting small The core team for the production of our first game for tablets within this studio consists of only two people, "starting small" was vital. This has been written about many times before by people who experienced starting a small studio and I had experienced this situation myself before on comparable occasions. As tempting as it is, starting development on a game without restriction about what the game should be, we knew we had to think very carefully about what two people could handle within a realistic timeframe. Starting common It is important not getting carried away by the possibilities for scope or gameplay complexity. A game where we would have had to research and prototype gameplay mechanics for months upfront wouldn't have been feasible. So, we opted for a genre that is well known, is always in demand and sets a clear objective for programming and production. Choice of Core Audience With the theme of Pavel Piezo we strayed from the usual core audience for the current breed of Hidden Object Games. A very limited budget for production told us that we couldn't compete with other productions for this core audience. So we opted to be more kid friendly with the theme and graphic, keep the scope of production in reasonable limits and choose a PoD that is of interest to players from other demographics, too. Choice of "Point of Difference" We were loving the idea of an "educational game" right from the start. It all came together when I discovered a recent study about peripheral learning. The described method integrates nicely with a HOG, we had something that would set our HOG apart from others and would make the game interesting to people beyond a specific demographic. HOGs are liked as casual games by a wide variety of age groups and the added bonus of getting to learn about foreign languages hopefully makes players of older demographics forgiving about the limited scope. Choice of Game Engine I have written about our choice of HTML5/JS as the Game Engine for Pavel Piezo in a previous article. I list it here under "What went right" because we had done a different project in HTML5/JS right before starting development of "Pavel Piezo" and that allowed us to immediately "jump in" on the programming. Plus, in the end it worked out fine. Coding This went like a charm. Being only two people, my colleague Sven was coding the whole thing from start to finish while I took care of game design, production, auxiliary art direction, organizational issues and everything else. Beside that I was able to help with programming as occasional sparring partner, tester, researcher and with coding additional small systems for the website, etc. Audio Production We outsourced audio to a local studio with experience in producing audio for games and audio books for children. The music, sound fx and the German version that we produced with two professional German speakers, friends of mine, were actually the first parts that were finished. For the other languages we found very friendly professional native speakers online, through various websites and searches. We found them all very competent, organized and helpful to the extent that they even pointed out translations that did not feel 100% natural to a native speaker. We did let everyone work with their preferred local studio or with their own equipment. The quality was flawless and the speed of delivery and even extra lines that were recorded as changes came up could not have been done flying people across the country. Estimated time for production We did not have a fixed budget for the production but instead aimed for reaching a certain degree of production value with minimum costs. It was clear that this would result in us doing tasks ourselves which could otherwise be outsourced. Once the game design and concept art were in place we evaluated the tasks and estimated the necessary time for production. In spite of troubles on the way (see below) and using up the buffer time I factored in we did hit that mark pretty accurately without heavy crunch. What Went Wrong Organizing the translations While we had a very capable professional translator working with us right from the start, I underestimated the amount of effort it took to translate the short sentences and phrases into the additional languages. It's one thing to translate the two words "scary ghost" to another language, but it may turn out to be better to use a different phrase or word once you can actually show a picture of that particular "scary ghost" to a native speaker. Of course, not every description, short as it may be, can be translated 1:1 and that caused extra effort with organisation as some phrases had to be honed later on. Artwork and Artists With this aspect of production, we were simply unlucky. We started out with a skilled artist for the concept drawings and other early steps. Unfortunately, he quickly realized that he did not have the technical skills required to produce the final artwork for the game in a timely manner. After that we had to look for a new artist who could jump in - not easy to find. The artist who then joined us as a freelancer had experience creating art for games and could produce art in a very fitting style for "Pavel Piezos" theme and audience. Unfortunately, he immensely underestimated the effort involved and soon it became clear that we would be approximately three levels short by the beginning of the time we set aside for fine tuning and bug hunting. After I did put a lot of time and effort into searching (again), we found a studio which had experience with HOGs and available capacity at that time. Although they did their best in the limited time available to capture the overall style of the artwork, composition and scheme, one can clearly see the breach between different levels in the game. HTML5 / HTML5-Audio / iOS Safari WebKit We ran into serious problems on our way which, at first, we thought to be "the usual" trouble with memory optimization. As we dug deeper and deeper into code and libraries it dawned on us that we did hit bugs and glitches within the underlying system, specifically Safari Webkit on iOS on different iPads (unless noted otherwise, all notes here refer to up-to-date versions between Nov. 2013 to Jan. 2014). We traced each of these glitches down to the point that we coded specific test cases with minimal code, some just five or six lines. As we observed the effects with these small routines and did not find a way to avoid them we concluded that they are in the underlying browser engine. If you recognize any of these and know that they are not in fact browser glitches and know how to avoid them, we would love to hear from you! The game has a lot of Graphics-Assets, so we're "unloading" assets after a level to keep the footprint in working memory within reasonable limits. Tests with XCodes profiler showed that "deleting" assets (in our case loaded by XML-HTTP-Request) left around 100kB allocated, no matter which technique we used to delete the object, null the object etc. Seems like iOS Safari WebKit always keeps some metadata in memory. We started out using HTML5-Audio. With the systems we used for development we observed that loading audio files with XML-HTTP-Request into the HTML5-Audio-Object used up about four times the memory of the size of the loaded file. Plus, the quality got muffled, audibly. To us it seemed that the browser engine somehow loaded the sound, unpacked it in memory and re-packed it in some lower quality. We were a bit baffled, to be honest. Well, that effect might be avoided by choosing some special encoding parameters (we did stick to Apple's documentation, though) but we simply opted to go with Phonegaps bridge to the native audio functions, which worked off the bat. To keep the file- and memory-clutter minimal we switched to audio sprites for the short sentences and vocabulary. Turns out that audio files can't be bigger than 20MB when loading into the browser engine. We had to cut some of them apart to meet this. The graphics in our game are the exact size that is needed for displaying them. We don't scale images or sprites. There are different sets for retina displays, etc. Nevertheless, somehow the canvas always did some kind of smoothing to the images when displaying them. There are a lot of posts out in the internet that suggest one or the other method of avoiding that effect and we tried a lot of them. From some testing we concluded that the iOS Safari Webkit simply ignores "...webkitImageSmoothingEnabled = false;" while honoring other directives for displaying images and sprites in canvas. We managed to work out a decent solution from all the helpful comments about this topic out there on the net. Lessons learned Besides the experience one gains during the production of a multi-language game there are two topics that I feel worth mentioning. Production Pipeline For the next production of a Pavel Piezo game, I will opt for finishing the (pre-)production in its entirety in our native language first. Of course we'll keep internationalization for the target languages in mind and work with preliminary translations for development and testing. Only after that will the final translations be done and the native speakers of the other languages be involved. This will allow for easier tweaks and changes during the first part and will present translators and speakers with a much clearer picture of the contents. As for the artwork, for upcoming productions we will employ an artist to do much more elaborate concept art at the beginning. While a "chair" might be drawn in this way or that way, the composition of elements in a scene, findable items within the scene, sizes and positions were not easy to communicate, even with providing rough concepts or finished previous levels. Our approach would have been fine and fitting if we didn't had to get additional artists mid-production. But to be prepared for eventual growth of the team and possible changes of members the visual composition has got to have solid prototyping. Choice of Game Engine We are happy with our choice of HTML5/JS for the production of "Pavel Piezo - Trip to the Kite Festival" and we will continue using HTML5 for projects where it fits. But, as I described, we feel we reached some limits of what is feasible with this combination at the moment. We want to go further, we want to have more animations, more sounds and simply a bigger scope in upcoming games and we decided that using a different, full-fledged game engine will fit productions like that better and will save effort in the end. Conclusion Despite all road bumps the production of "Pavel Piezo - Trip to the Kite Festival" was a great experience. The game was finished in time and I think that everyone who helped this to come to fruition can be proud of having been part of creating a game which is fun for all ages and helps with learning foreign languages; the latter being a topic that gets more and more important in our time. For any flaws one might find with the methods used or with the game itself: I am entirely to blame, personally. The team is very excited to see how the game is received by its audience. We welcome any feedback, we look forward to releasing "Pavel Piezo - Trip to the Kite Festival" on additional platforms and to producing additional games in the Pavel Piezo series. Infos and Numbers Developer: intolabs GmbH Publisher: "Phase 3: Profit" Release: February 2014 (iOS/iPad) Platforms: iOS/iPad (other platforms are planned for later 2014) Development: Sven Toepke and Carsten Germer Outside help: Translator, audio studio, eight native speakers, two graphic artists, art studio Length of development: Ten months Development tools: HTML5, Javascript, jQuery, createJS suite, Cordova, ... Lines of code: 57976 in 112 files (Javascript, HTML, CSS) Article Update Log 25 Feb 2014: Initial release 13 Mar 2014: Clarification about (pre-)production and translations
  4. After releasing our last game (Pavel Piezo - Trip to the Kite Festival) we began work to finish MusiGuess. MusiGuess is a simple game where the player is presented with four cover arts, hears a preview of one track from one of the albums and has to pick the right cover to which the track belongs. It is a very addictive mechanic and loads of fun for short sessions in-between. The idea has been around our office for some time now and we had built various prototypes for us to play around with. In this article I won't go into details about the game, basically everything about the core mechanic is said in the preceding paragraph. I am going to share an easy to use technology that improved performance with client-server communication from "sometimes stalling for a minute" to "lightning fast". "But, Carsten, just program and set up your servers accordingly?" Yes, I hear you and am very aware of that, but the servers we get a large chunk of our games data from are not ours to tinker with... MusiGuess uses several Top-Albums-Lists for the game. You can have your riddles assembled from "Top 50", "Rap / Hip Hop", "Rock", "Electronic" and so on. These lists are queried from a public interface on iTunes(r) which provides nifty RSS feeds for all kinds of product information from the iTunes Store(r) in XML or JSON (https://rss.itunes.apple.com/). If you mark the promotional resources correctly as being from iTunes(r) and provide your users with links to buy the displayed media in the iTunes Store(r), use of these promotional resources is covered within the affiliate guidelines. This API for RSS feeds is, at times, slow if it receives multiple queries from the same client/IP within a short timespan. Of course I do not have detailed technical information, but throttling makes perfect sense as protection against misuse and DOS-attacks. Though response times never interfered with the gameplay of the actual riddles in MusiGuess, it could make activating or updating many lists for some users (I can haz all, nau?!) tedious. Plus, MusiGuess just needs a specific small subset of the information provided in the RSS. Plus, we don't want MusiGuess (our players) to stress the API unduly. Plus, every individual device needs the JSON as individual JSONP (JSON with padding), which the API is completely capable of but would mean extra stress on its internal caching methods. The solution: Forward-caching the JSON objects with NGINX on our dedicated game-server. The server system I am using Nginx as forward-cache / -proxy. You can utilize a host of different systems to implement the discussed techniques (including "Apache HTTP Server", SQUID, Varnish and systems you code yourself) but to date I find Nginx the most powerful and easy to set up working horse that needs the least resources. Learn more via their wikipedia article (http://en.wikipedia.org/wiki/Nginx). Why forward caching? Delivering data over the internet via HTTP(S) is a common way to go nowadays. All kinds of data, not only in the format HTML, but for instance XML, RSS or JSON, and cache-servers were adapted to deal with these kinds of objects very well. The wikipedia page about web caches (http://en.wikipedia.org/wiki/Web_cache) explains the basics quite nicely. If you have a server/software that delivers the same data-object to a large number of clients, you don't need to optimize that server to gain response time. You can simply put a forward-proxy "in front" of that server. Requests hit the proxy and the proxy checks if it has a "recent version" of the requested object (the definition of "recent" can be configured). Only if the proxy does not have an actual version of the requested object does it ask your source server/software for one, stores it in its "cache" then hands it on to the original requester. After that the forward proxy will hand the object to every requester without bothering your source server until the configured definition of "recent / actual" is no longer valid for that specific chunk of data. What's the deal with JSONP? JSON is a convenient data format for transmission via HTTP(S) and processing with JavaScript (http://en.wikipedia.org/wiki/JSON). Now, "JSONP or 'JSON with padding' is a communication technique used in JavaScript programs ... to request data from a server in a different domain, something prohibited by typical web browsers because of the "same-origin policy." (http://en.wikipedia.org/wiki/JSONP). Short story: The answer to a JSONP-request has to be wrapped in a unique callback for every individual requester and for every request. This fact makes data in JSONP inconvenient to cache, as it can never be guaranteed to be the same for any two requests. Although the raw data that is transmitted might very well be the same (perfect for caching) the unique wrapping with a callback is most likely not! How do we manage to still use full forward-caching? The forward-proxy requests the data from the original source in plain JSON, caches it and takes care of the JSONP-wrapping for every individual client and request itself. The Nginx configuration For trying this yourself with the configuration I'm showing, you will need a recent version of free Nginx (http://nginx.org/) with the optional HttpEchoModule (http://wiki.nginx.org/HttpEchoModule). I'm not going to discuss the general configuration of Nginx in detail, I will explain the actual JSON/P parts in depth. I also simplified and abstracted this from our specific installation to generalize the concept for easier use in different applications. # Proxy my original JSON data server location /api_1_0/mapdata { # This is running on the Nginx cache-server so it will called by something like # http://nginx.my-gameserver.com/api_1_0/mapdata?area=5&viewwidth=8 # Deactivating GZIP compression between Nginx and original source. # The setup can't handle GZIP chunks with echo_before (a glitch in nginx or echo as of 04.14.2014) proxy_set_header Accept-Encoding "deflate"; # Injecting the current callback and wrapping into the answer. # This is the magic part, that takes care of the JSONP wrapping for the individual clients and requests! if ($arg_callback) { echo_before_body -n '$arg_callback('; # The actual data from the cache or the original data source will automatically be inserted at this point echo_after_body ');'; } # Yes, that's all there is to do :-) # Specifying the key under which the JSON data from the original source is cached. # This has to be done to ignore $arg_callback in the default cache_key. We utilize only params we specifically need. proxy_cache_key $scheme$proxy_host$uri$arg_area$arg_viewwidth; # I advise to always include "$scheme$proxy_host$uri" in a cache_key to be able to add other API versions (e.g. api_2_3) # and other data points (e.g. /leaderboard) later, without having to rely on additional parameters. # Telling Nginx were to request the actual source data (JSON) from. proxy_pass http://php-apache.my-gameserver.com/map/$arg_area/$arg_viewidth/json; } You may have noticed that the original data source (php-apache.my-gameserver.com) uses all parameters fully embedded in the URL and the forward-cache (nginx.my-gameserver.com) gets the parameters as HTTP-GET query string. This has no deeper meaning besides it was quicker and easier for me to work with the $arg_* in the configuration. It is well possible to match APIs "query string" / "ULR embedded" any way you see fit within the configuration of your forward-proxy. Design of HTTP-APIs, RESTful, RESTlike etc. are well discussed topics. My advice would be to read up on all that and decide what fits best for your project. Any more gritty details? There are some things you should be aware of when using Nginx as forward proxy and when implementing this technique in general. I'll continue to discuss based on Nginx, version 04.14.2014, things may have changed since then or are different in other systems. If you base your configuration of the "location /.../ { ... }" in Nginx on e.g. an existing boilerplate (Copy&Paste), be aware of "proxy_redirect default;" within this locations block. "proxy_redirect default" cannot be used with a "proxy_pass" directive that uses $arg_* as in the example above. Simply remove it or comment it out. If you still want to see the IP-Address of the original request from the client in your source server's logfiles, you'll need to add a specific header that is processed by most major software for log-analysis. > proxy_set_header X-Real-IP $remote_addr; HTTP-headers coming from the requesting client can mess with your caching. For instance, when you use "shift-reload" in your browser a header is sent along with the request to specifically instruct the server to not use cached data as an answer. In our case, we want to suppress that, if only to allow "maximum efficiency caching". > proxy_ignore_headers X-Accel-Expires Expires Cache-Control Set-Cookie; Similarly, your source server may send a bunch of headers (many headers are sent automatically by web servers) that have no use for your project. If it's not needed, it eats up bandwidth and you may want to suppress these in the answer to the client. With Nginx you can do that by adding the directive "proxy_hide_header header-i-want-to-suppress" to that location's block. You can find all headers that are sent if you request the data with an ordinary browser from your forward-proxy and dig around in the "page information", "developer tools" or similar. Modern browsers have some function that show these. Additionally, you may want to adjust how long your cached data is valid, how to deal with stale cache answers that can't be refreshed from the source server in time, etc. These are topics that are covered within the documentation of the cache systems and very often the defaults will suffice without much adjustment. In conclusion Do you have a game server which is queried for the recent version of the map of your MMSG by thousands of clients every few seconds and your code can't cope with that amount of requests? Forward cache (reverse cache) the JSON or XML object with Nginx and your game servers logic only has to deliver a single object every few seconds. Got problems with utilizing a third party API because it does not provide JSONP itself? Set up Nginx as a forward proxy and pad the JSON yourself. As long as you have an eye on JSONP's security concerns (http://en.wikipedia.org/wiki/JSONP#Security_concerns) a lot of problems can be tackled this way. I hope to have helped spread the word and that fellow devs may remember "I have read something about that..." when encountering challenges of that kind. Article Update Log 06.03.2014: Initial release About MusiGuess As of 06.03.2014 there is no promotional website or similar yet. The game will be released alongside accompanying material in 2014 for iOS.
  5. What are you trying to do more exactly, shinypixel? ("...that I can read/write to it")   Reading sounds like requesting a file with the normal methods (HTTP/S). "...that can be a security issue..." but it's usually not. You have to take care that your webserver software is uptodate and your configuration doesn't leave any vulnerabilities. That's very achievable and much can be learned by reading docs and forums.   "Write" on the other hand is a bit more tricky. I agree with nfactorial and spazzarama, that suggets a proper API (REST*, RPC) with access control. On the other hand, that is not as difficult as it may seem, because it has been done many times before. You'll find lots of information on the net and you can learn a great deal.   If you are not set on Microsoft technologies for your backend, I'd suggest Apache/MySQL/PHP (WAMP, MAMP, LAMP). It's easy to set up, get into and have quick results when prototyping.
  • Advertisement