rotatengine.js

Project report done in a Game Engines class at ITU.
This site’s template is a bit outdated and a PDF version
may look better, which can be downloaded from the
Google Drive source document,
but there the embedded videos are missing.

 

Rotatengine is a JavaScript framework intended to facilitate the creation of games, for mobile touch devices, that require the player to spin around in circles, in different directions, to reach various goals.  As the player turns around, holding the device in front of him or her with arms stretched out, the game’s content moves accordingly as if it is attached to a cylinder or a sphere, within which the player is standing.

 

Motivation

Young children often spin around as a form of play, which they perform for the sheer joy of it and maybe the resulting dizzying effect as well[1].  Many forms of dance involve spinning around to various degrees (!) at different moments in time, and people usually dance for their enjoyment.  Spinning around can also be a part of religious acts, whether they be Tibetan[2] or Islamic[3].  The act of spinning in circles has even been promoted as a means towards weight loss[4].

So the impulse to spin around, for different reasons and in various contexts, seems to be quite fundamental in us humans.  Usually the act is related to fun and play, and rotatengine.js is based on the idea of encouraging, and maybe structuring, object play[5] that requires or offers spinning around.

Many types of games can be conceived, based on this frame of play and implemented with this kind of a game engine.  One kind can include textual elements that are arranged in a circle and the player must tap them in the correct order to organize them into a coherent goal.  Another could present the player with images that she must tap on when certain conditions are met, like when the image aligns with another fixed image or text or sound.

Here are outlined more specifically a few game ideas:

  • Rotabet:  The player is presented with the letters of the alphabet in a random order, spread out in a circle around him, as if he is standing within a cylinder where the letters are painted on the wall and his view into that world is through the mobile device screen.  By rotating the device in different directions and angles, the player sees different portions of the cylinder wall and has the goal of tapping the letters in the correct alphabetical order.  As the player taps the letters they are arranged sequentially in a fixed position on the screen, so he sees the progression towards the goal:  The letters of the alphabet being arranged in correct order.A game like this utilizing rotatengine.js can then offer various gameplay mechanics, such as penalizing incorrect choices (taps) by cropping off the already accomplished result, rewarding for so and so many correct choices in a row by then allowing an incorrect choice without penalty, and giving an overall score based on how quickly the goal was reached.  Levels can be made increasingly difficult, for example by varying the required player response time; at first removing the choices (letters) as they are chosen, to make the level easier as it progresses, and then at later levels, leave all choices in to make the level constantly difficult.  Fonts could change with level progression, with at first a large and readable sans-serif font, then later on, less (quickly) readable script fonts.This could be considered as an educational game, where the player gets practice and fluency with the alphabet.  Rotabet is actually the initial idea that inspired the creation of rotatengine.js
  • Rotaquote, a quotes game:  The player sees the name of a known person fixed on the screen and then a few words scattered around him or her in random order.  Here the goal would be to tap the words in an order that would arrange them into a (famous) quote that is attributed to the named person.
  • Similar to Quotabet, a game could be created that is based on poetry instead of quotes.  Here the player would have to assemble (known) poems, line by line.  Each part of the poem (paragraph) could form one level of the game.  If the player gets so and so many errors, she will for example have to start at the previous level.  The goal is to assemble the whole poem.
  • Form grammatically correct sentences:  Similar to the quotes and poetry games, the player is presented with a soup of words she has to arrange into any of possibly several grammatically correct sentences.
  • Anagram:  Player is given the task of assembling a given number of anagrams from a set of letters she can spin around, for example:  emit, item, mite, time.
  • Palindrome:  Given a random sequence of letters, the player has to arrange them into a palindrome, for example:  abba, radar, kayak.
  • Rotatag – match pictures with tags:  Various photo hosting services, like Flickr or Instagram, offers users to (#) tag pictures with descriptive words.  Those services also offer public programming interfaces (APIs) and a game could use them to pick a few random pictures each time to spread around the player, then pick a tag from one of the pictures to place in a fixed position on the screen.  The player is then to guess from which picture the tag came from by tapping on it.
  • Match a picture to a written word:  Around the player, on the walls of the cylinder, are visual representations of various objects and beings, such as a chair or a duck.  A word appears on the screen in a fixed position and the player is to tap on the visual that matches that word.  So if the word “horse” appears, then a player must spin around until he sees a picture of a horse and tap it, with a resulting encouragement in the form of a cheering sound or some in game value, such as a trophy.This type of a game could be suitable for young children learning to read or those learning a new language.
  • Tap a graphic matching with the sound you just heard:  Five visuals are spread around the player and at regular intervals, one of five matching sounds is played and the player must in time rotate to the matching graphic and tap it.  So for example, if the player hears a goat screaming, she must rotate to the position where the drawing of a goat is located and tap it in time.  Progressing levels decrease the required response time and the goal is to stay playing as long as possible without an error or too long a response time.This type of game is inspired by the audio game Bop It[6], originally implemented in specialized hardware (which this author has tried) and is now apparently available in an iOS version[7] and a clone is available for Android[8].  But those touch-device implementations don’t require full body movement, like the game proposed here does, though from their description they do seem to require some device movement by recognising hand gestures (possibly using Dynamic Time Warping (DTW) and Hidden Markov Models[9], which were considered for the implementation for rotatengine.js but deemed not a good fit, as they seem best for sensing spontaneous, short lived movements but the engine discussed here requires continuous monitoring of movement and position – more on that below).

 

Implementation

Rotatengine is dependent on accessing the device’s sensors in order to position the game world (cylinder or sphere) according the players’ movements.  While the engine could be implemented for one particular platform, for example iOS, in code native to it and thus gaining the highest possible speed, the decision was made to try and target more than one, if not all platforms by using JavaScript, HTML5 and CSS3, to be run in each platform’s web view.

JavaScript is increasingly gaining access to the graphics acceleration hardware on the platforms it runs.  Though the performance of applications implemented in JavaScript and HTML is still, and probably always will be, less than that of native applications, the graphics requirements of rotatengine.js are quite modest and so it might not gain much from a native implementation – investigation of that possibility is currently outside the scope of this project.

Visual rendering and interaction

At the current stage of implementation, focus has been on the part that handles rendering of elements in the desired manner and the interaction with those rendered elements by the player’s circular movements.

Choice of technology

The game world provided by rotatengine.js must in some ways give a three dimensional illusion, where the player is to sense that he is the pivot around which game elements rotate as he spins in circles.  Modern desktop browsers provide the WebGL 3D graphics programming interface (API), which uses the HTML5 canvas element and provides code execution on a computer’s Graphics Processing Unit (GPU).  That could be an obvious choice for an engine that manages content in 3D.  Mobile devices have lacked support for WebGL[10], though the most recent versions of web views on some platforms are now supporting it, with iOS being a notable exception[11].  So to reach the widest range of mobile devices, it is worthwhile to consider other options for 3D content rendition.

The CSS3 specification includes a module that defines 3D transforms that “allows elements styled with CSS to be transformed in two-dimensional or three-dimensional space”[12] and CSS3 3D Transforms are supported on most of the recent mobile platforms[13].  Given that wide support and the simplicity of arranging various types of HTML elements – letters and images, as in the game ideas listed above – with the same set of CSS rules, it seems to be a good choice to base the visual implementation of rotatengine.js on CSS3 3D transforms.

Interactive animation mechanics

A couple of approaches have been considered to manage the objects in the game world as the player interacts with it.

The first one considered is inspired by the Cover Flow[14] graphical user interface, where off-screen game objects would wait in line, decoupled from the animation mechanism, until next on screen  Then they would be coupled with the animation and flow across the screen, until decoupled again at the other end.  The objects would be incrementally skewed to either side and translated in distance from the viewer, as they flow across the screen to simulate a cylindrical / circular 3D effect.  This approach could have the benefit of allowing virtually infinitely many game objects, that would wait in the off screen queues for the player to pass by them while he rotates, and then more than one full circle could be required to display all objects.

rotaimage10

The Cover Flow interface[15]

Another approach is to arrange the elements on a circle using the trigonometric functions sine and cosine.  This is the method currently implemented, where each item is assigned an amount of radians by dividing the amount of radians in a full circle (2 * π) by the number of game elements.  Then the x  and – z coordinates are calculated for each element by applying cosine  and – sine , respectively, to it’s radian value multiplied by the integer value of it’s sequential order.  The coordinates are multiplied by a radius which itself is a scaling of the view’s width.  So now the elements are spread evenly around a circle that is roughly double the width of the scene.  Each item is rotated individually by it’s radian value minus  π / 2  to have it facing inside the circle.  The radius value is added to each z  coordinate to have the viewer inside the circle, close to it’s perimeter.  A simplified version of the relevant code is as follows:

       var perspective = viewWidth / 2;
       var radius = viewWidth * 1.2;
       container.css({"transform": "perspective("+perspective+")"});
       items.each(function(i){
            // let's go clockwise, thus fullCircleRadins - ...
            var thisItemRadians =
               fullCircleRadians - (self.radiansPerItem * i) + viewRotation;
            var x = Math.cos(thisItemRadians) * radius;
            var z = - Math.sin(thisItemRadians) * radius;
            var transform =  
                "perspective("+ (perspective) +") " +
                "translateZ("+(z + radius)+"px) " +                
                "translateX("+(x)+"px) " +
                "rotateY("+(thisItemRadians - (Math.PI/2))+"rad)";
            $(this).css({"transform": transform});
       });

Initial testing of this game element rendition was performed in a desktop browser, where interaction input was read from mouse movement and keyboard button presses.  One animation anomaly that became apparent during this testing was that if CSS3 transition-duration was set to high and fast movements were made, the elements would spin around themselves and take a shorter path to their new destination, over the circle’s area, instead of animating smoothly along its perimeter.  Setting the duration speed to 0.1 seconds solved this for most animation speeds, and zero seconds also but then sacrificing a little in animation smoothness.

Here the radius is subtracted from the z value, instead of adding to it, to have the viewer / camera outside the circle with a full view of it.
Here the radius is subtracted from the z value, instead of adding to it, to have the viewer / camera outside the circle with a full view of it.

When most flaws had been ironed out and the elements were animating in the intended manner in a desktop browser with mouse interaction, it was time to proceed to testing on mobile devices with input from their sensors.

Differences between sensors and platforms

Mobile devices commonly offer three types of sensors[16] that provide information on their orientation – magnetometer (compass), accelerometer and gyroscope – and together those sensors can be referred to as an Inertial Measurement Unit (IMU)[17].  Of these, the compass is a straightforward choice for input to the rotatengine.js game world, as it provides information on the device’s heading in degrees.

Magnetometers on mobile devices can be inaccurate when used indoors, due to interference from the building[18].  That would not be problematic for rotatengine.js as it does not need an accurate measurement of heading, but rather a responsive and mostly stable and consistent reading of where the device is pointed.

Apache Cordova[19], the open source engine behind PhoneGap, was used to package rotatengine.js into applications to be run on the Android and iOS mobile platforms.  NetBeans with it’s recent Cordova support was used to manage that process[20].

Rotatengine on the iOS simulator, run through the built-in Cordova support in NetBeans.
Rotatengine on the iOS simulator, run through the built-in Cordova support in NetBeans.

 

A sample application of rotatengine.js running on Android and iOS, receiving periodic heading input via the Cordova API[21], performed correctly but not with the desired responsiveness; when moving around in circles holding the device with hands stretched out, the updates of the game world objects were quite slow and somewhat jittery and equally so on both Android (Nexus 4) and iOS (iPad 2) devices.  See video recordings of tests:

 

Though Cordova’s API offers the option to specify the update frequency from the compass, further debugging showed that updates were in fact being delivered around every 200 milliseconds, even though a 50 ms update interval was requested.  This seems to be a hardware limitation on both platforms tested and a 200 ms interval is unacceptably long for a smooth animation and responsive updates.

A simple attempt was made to extrapolate future changes in rotation with shorter intervals, from the previous update interval, until the next update would be received from the compass.  Those future changes are calculated by dividing the delta of the previous two compass updates by four, and the scene is rotated by that fraction every 50 milliseconds.  Those intermediate updates from extrapolated values did not result in much improvement when run on a device, and as expected, an initial halt of animation is visible when rotation is started or direction is changed and two compass readings are being collected (with their 200 ms interval) for further extrapolation.  See video recording of test:

Testing raw compass sensor data as input to rotatengine.js
Testing raw compass sensor data as input to rotatengine.js

 

Gyroscopes have recently become available as sensors in mobile phones, first in the iPhone4[22] and then in various Android devices.  That kind of a sensor gives information on orientation changes[23], so it was the next option as input to rotatengine.js.  Here, Cordova’s API was bypassed as HTML5 provides direct access to updates from the gyroscope (via callback function attached to window.ondeviceorientation)[24].  The device’s heading is read from one of three values returned from the sensor (alpha) to which the scene is rotated.

The gyroscope on the iOS devices tested, iPhone 4s and iPad 2, proved to be quite stable and it’s raw data readings provided smooth updates of the game objects, even without any CSS3 transition-duration and it’s smoothing effect of animation easing[25].  See test video recording:

The same can not be said about the results from the Android device tested (Nexus 4), where orientation updates were very jittery and unstable, even when the device was being held still, the game objects would jump around constantly.  See test video recording:

Using the gyroscope with the current implementation would be adequate for targeting iOS devices, but if the aim is for a more cross platform solution, then the raw data from the sensors needs to be handled in some manner that both provides stability and responsiveness.  One approach considered was to implement a basic low pass filter[26] on the data returned from the sensors, but having something to filter requires first the accumulation of sensor data to then apply the filter on, and that results in an initial delay and a lack of responsiveness.

A viable approach for the use of sensors to update game object positions in a responsive and stable manner, on multiple platforms, could be to fuse the information from multiple sensors[27] and apply advanced filtering on the data with statistical estimates of the real heading.  The gyroscope and accelerometer can be combined to form a 6-axis inertial sensor (roll, pitch, yaw and vertical, lateral, longitudinal acceleration).  Two prominent methods for integrating gyro and accelerometer readings are the Kalman filter[28] and the Complementary filter, the latter is easier to understand and implement[29] and is said to give similar results[30].   Also, the lighter implementation of the Complementary filter would require less processing power, and that is an important consideration for the battery consumption on mobile devices.

The next step in developing the rotational interaction with game elements in rotatengine.js would be to apply this fusion of the gyroscope and accelerometer with either the Kalman or Complementary filter[31].  The Complementary filter’s simplicity makes it a tempting first choice.

Next steps

Further development of rotatengine.js includes reacting to interaction with game elements by touch, where events would be fired that a game implementation can register for and different element behaviours could be defined for those events, like animating to a different place or disappearing.

Also, the game world could be rendered in a spherical fashion, in addition to the cylindrical one, where navigation of game elements would be done by tilting the device up- and downwards, along with the basic circular motion.  Options for this kind of spherical world could include the definition of how many layers of spheres surround the player and whether the spheres are shrinking towards the player, to allow for a more dynamic and engaging environment.

Modularization

In the first phase of the implementation discussed here, attention to code structure for the project has been minimal and has at most consisted of encapsulating functionality in object literals and function closures[32].  For further development, the module pattern[33] has been considered as a way to organise the code.  For inter-module communication the mediator pattern[34] is a choice.

The module pattern fits well into the Entity component system (ECS)[35] design pattern, which favors composition over inheritance.  When designing a game engine that may handle entities that have many different variations, an object-oriented approach may lead to “deep unnatural object hierarchies with lots of overridden methods”[36].  A game engine based on the ECS pattern, however, “provides the ultimate flexibility in game design” where you “mix and match the pre-built functionality (components) to suit your needs”[37].

With rotatengine.js based on the ECS pattern, a game using it can define behaviour and functionality by referencing different modules, for example specifying how game objects respond when a player taps on them.  Work on the filtered sensor fusion described above should continue within a separate module that can, when implemented, be swapped with the direct, unfiltered single-sensor reading implementation currently in use.

For managing modules within rotatengine.js, the Asynchronous Module Definition (AMD) API[38] has been chosen as it works better in the browser / webview than other JavaScript Object APIs, like CommonJS and “the AMD execution model is better aligned with how ECMAScript Harmony modules are being specified. … AMD’s code execution behaviour is more future compatible”[39].  Work has started on modularising the current implementation, that can be seen in the project’s js/rotatengine directory.

Data schema and automatic content generation interfaces

Each level instance in rotatengine.js contains game objects created from data defined in a JSON configuration file.  For now, the definition of how the data is structured is arbitrary, to have something running as quickly as possible.  But when the engine should be ready for use by a party not involved in it’s development, some means is needed to communicate the required structure of the configuration files.

To define the structure of configuration files for rotatengine.js, the JSON Schema specification[40] has been considered.  To ease the creation of a schema definition, there can be found tools based on that specification, to generate a definition from an example data file[41].

Declaring data files, based on the schema, could be done manually by reading the schema and carefully adhering to it in a text editor.  A specialised user interface for entering the level data according to the schema could help a level designer get up to speed.  User interfaces can be automatically generated from a schema definition and the Metawidget object/user interface mapping tool[42] could be a helpful choice in that regard, with it’s JSON Schema UI Generator[43].  With that tool, the engine could include simple webpages, that allow data entry resulting in a JSON string conforming to the given JSON Schema[44], which could then be saved to a configuration file ready for use[45].

 

Conclusion

rotatengine.js is a specialised engine designed for limited game mechanics, where the player is to spin around in circles and interact with game objects as they rotate around him.  But within that limitation, it is possible to conceive diverse types of games, as the examples above show.  The engine will hopefully lead to a unique variety of play and games.

As of this writing, the runnable code can be initiated by opening the index.html file in the project’s root, or by compiling it into a mobile application with Apache Cordova or Adobe PhoneGap.  As mentioned previously, work has started on modularizing that same code in the js/rotatengine directory, but it is currently not in a runnable state.

The project can be found on the attached optical disk and online at:

https://github.com/bthj/rotatengine.js

 

IT University of Copenhagen
Game Engines course – instructor:  Mark J. Nelson
autumn 2013
Björn Þór Jónsson (bjrr@itu.dk)


[1] “Ilinx is a kind of play” that “creates a temporary disruption of perception, as with vertigo, dizziness, or disorienting changes in direction of movement.”  http://en.wikipedia.org/wiki/Ilinx

[2] First of Five Tibetan Rites involves spinning around “until you become slightly dizzy”:
http://en.wikipedia.org/wiki/Five_Tibetan_Rites#First_Rite

[3] “Sufi whirling is a form of … physically active meditation … spinning one’s body in repetitive circles, which has been seen as a symbolic imitation of planets in the Solar System orbiting the sun”

http://en.wikipedia.org/wiki/Sufi_whirling

[4] “How Spinning Aroundin a CircleLike a 4-year old Child will Skyrocket Your Weight Loss Success“
http://www.weightlossguideforwomen.com/spinreport/SpinReport.pdf

[5] Physical activity with toys in object play:  http://en.wikipedia.org/wiki/Toy#Physical_activity

[6] Bop It audio game / toy:  http://en.wikipedia.org/wiki/Bop_It

[9] A plethora of articles can be found on the subject of using Dynamic Time Warping and Hidden Markov Models for recognising gestures, for example:

“Smartphone-enabled Gestural Interaction with Multi-Modal Smart-Home Systems”

http://tilowestermann.eu/files/Diplomarbeit.pdf

“Online Context Recognition in Multisensor Systems using Dynamic Time Warping”

http://dro.deakin.edu.au/eserv/DU:30044625/venkatesh-onlinecontext-2005.pdf

“Motion-based Gesture Recognition with an Accelerometer”

https://code.google.com/p/accelges/downloads/detail?name=ThesisPaper.pdf

“A Novel Accelerometer-based Gesture Recognition System”

https://tspace.library.utoronto.ca/bitstream/1807/25403/3/Akl_Ahmad_201011_MASc_thesis.pdf

“Gesture Recognition with a 3-D Accelerometer”

http://www.cs.zju.edu.cn/~gpan/publication/2009-UIC-gesture.pdf

“uWave: Accelerometer-based personalized gesture recognition and its applications”

http://sclab.yonsei.ac.kr/courses/10TPR/10TPR.files/uWave_Accelerometer_based%20personalized%20gesture%20recognition%20and%20its%20applications.pdf

“Improving Accuracy and Practicality of Accelerometer-Based Hand Gesture Recognition”

http://www.iuiconf.org/Documents/IUI2013-WS-Smartobjects.pdf

“Using an Accelerometer Sensor to Measure Human Hand Motion”

http://www-mtl.mit.edu/researchgroups/MEngTP/Graham_Thesis.pdf

[10] CocoonJS is an interesting technology that makes up for the lack of WebGL support by bridging into native OpenGL libraries:  https://www.ludei.com/cocoonjs/

[11] Compatibility table for support of WebGL in desktop and mobile browsers:http://caniuse.com/webgl

[12] CSS Transforms Module Level 1:  http://www.w3.org/TR/css-transforms-1/

[13] CSS3 3D Transforms support:  http://caniuse.com/#feat=transforms3d

[16] “A Survey of Mobile Phone Sensing”  http://www.cs.dartmouth.edu/~campbell/papers/survey.pdf

[18] Interestingly, disturbances in the Earth’s magnetic field within buildings can used to advantage when positioning devices within them:

Startup Uses a Smartphone Compass to Track People Indoors

http://www.technologyreview.com/news/428494/startup-uses-a-smartphone-compass-to-track-people-indoors/

“Indoor Positioning Using a Mobile Phone with an Integrated Accelerometer and Digital Compass”

http://xldb.fc.ul.pt/xldb/publications/Pombinho.etal:IndoorPositioning:2010_document.pdf

„Making Indoor Maps with Portable Accelerometer and Magnetometer”

http://www.ocf.berkeley.edu/~xuanyg/IndoorMap_UPINLBS2010.pdf

[19] „Apache Cordova is a set of device APIs that allow a mobile app developer to access native device function such as the camera or accelerometer from JavaScript“:  http://cordova.apache.org

[20] NetBeans 7.4 can build HTML5 project as native Android or iOS application  http://wiki.netbeans.org/MobileBrowsers#Cordova_2

[21] Cordova API: At a regular interval, get the compass heading in degrees:

http://cordova.apache.org/docs/en/3.2.0/cordova_compass_compass.md.html#compass.watchHeading

[22] Steve Jobs demonstrates iPhone4’s gyroscope capabilities:  http://www.youtube.com/watch?v=ORcu-c-qnjg

[23] “A gyroscope measures either changes in orientation (regular gyro or integrating rate gyro) or changes in rotational velocity (rate gyro)”  – http://electronics.stackexchange.com/questions/36589

[24] DeviceOrientation Event Specification:  http://www.w3.org/TR/orientation-event/

[26] Example of a low-pass filter for smoothing sensor data:  http://stackoverflow.com/a/5780505/169858

[27] Google Tech Talk:  “Sensor Fusion on Android Devices: A Revolution in Motion Processing”http://www.youtube.com/watch?v=C7JQ7Rpwn2k

[28] „The Kalman filter, also known as linear quadratic estimation (LQE), is an algorithm that uses a series of measurements observed over time, containing noise (random variations) and other inaccuracies, and produces estimates of unknown variables that tend to be more precise than those based on a single measurement alone.“  http://en.wikipedia.org/wiki/Kalman_filter

[29] “Reading a IMU Without Kalman: The Complementary Filter”  http://www.pieter-jan.com/node/11

“Android Sensor Fusion Tutorial”  http://www.thousand-thoughts.com/2012/03/android-sensor-fusion-tutorial/

[30] „I have used both of them and find little difference between them. The Complimentary filter is much easier to use, tweak and understand. Also it uses much less code…“ –http://www.hobbytronics.co.uk/accelerometer-gyro

„In my opinion the complementary filter can substitue the Kalaman filter. It is more easy, more fast. The Kalman filter is the best filter, also from the theorical point of view, but the its complexity is too much….“ – http://letsmakerobots.com/node/29121

“The Balance Filter – A Simple Solution for Integrating Accelerometer and Gyroscope Measurements for a Balancing Platform”  http://web.mit.edu/scolton/www/filter.pdf

[31] An interesting practical application of the Kalman filter is the Android app Steady compass, which has the description that “sensor data is treated by a Kalman filter in order to obtain superior stability in readings”:

https://play.google.com/store/apps/details?id=com.netpatia.android.filteredcompass

[32] “JavaScript Patterns & Grokking Closures!”  http://www.unicodegirl.com/javascript-patterns-and-closure.html

[40] JSON Schema:  http://json-schema.org

[41] JSON Schema.net – http://www.jsonschema.net

[42] Metawidget:  http://metawidget.org

[45] An HTML5 saveAs() FileSaver implementation:  https://github.com/eligrey/FileSaver.js

Loading, Editing, and Saving a Text File in HTML5 Using Javascript:http://thiscouldbebetter.wordpress.com/2012/12/18/loading-editing-and-saving-a-text-file-in-html5-using-javascrip/

 

Appendix

 

Other smaller projects in the Game Engines class:

Project 1:  Platformer game engine

Plafgine

For the first programming assignment in Game Engines I’ve implemented a platformer engine in JavaScript and used the Canvas element in HTML5.

The main components of the engine are four pseudo-classes / functions (JavaScript only has the notion of functions):  Player, Platform, GameLoop and GameOver.  Those classes and supporting variables / data are encapsulated in another function called Plafgine (plat-former-engine) for closure.

At the top of plafgine.js are a few configuration variables to define the level, which could be factored into another file:

  • defaultPlayerPosition:  Defines the size of the main player and where it is positioned initially.

  • enemyPositions:  Positions for the enemies and their sizes.

  • platformDefinitions:  Placement of the platforms.

  • defaultEnemyAutomation:  This is maybe an interesting experiment using the dynamic nature of JavaScript to have the behaviour of enemies configurable by plugging in a function that implements their movement.

There are no real physics in this platformer and it rather implements pseudo-physics by starting a jump at a fixed speed and then decreasing it on each game loop, until the jump speed reaches zero, then a fall speed is incremented until collision with a platform or the ground happens.  Those are the jump, checkJump, checkFall, fallStop functions within the player object.

Different instances of the same implementation of the Player object are used for both the main player and the enemies (NPC), with their configurations differing in setting whether they are automated and then with the added behaviour-function mentioned above.  Some sort of class inheritance could have been a good idea here.

The collision detection is as inefficient as can be where player collisions are checked against all platforms and all other players on each game loop.  Spatial segmentation of what to check against would of course be better for any reasonably sized level.

Control of the main character is handled by registering pressed keys into a state variable and then reading those states on each game loop (in the player implementation) and moving the character accordingly.

Camera movement is implemented by keeping the main character still and moving all other game world objects in the opposite direction when the character has reached a certain threshold on the screen.  That threshold is in fact centered on the screen so the character is pretty much always in the horizontal center.  There are glitches in the implementation of this camera movement that can almost always be reproduced when jumping from the highest platform; then the player doesn’t fall completely to the ground, but that can be fixed by jumping again! – the cause of this should be investigated in another iteration.

Timing is used to determine when to update player sprites based on their activity; when a predefined amount of time has elapsed the portion of the sprite to render is updated.

Same goes for the lives bookkeeping, only when a set interval has elapsed can the count of lives be decreased, so all lives don’t disappear instantly when multiple characters collisions are fired.  So if the main character hits an enemy he loses one life and loses one again if he keeps hitting an enemy when the set interval has elapsed.  Unless the main player hits the enemy from the top – jumps on top of him – then the enemy gets killed.

Then the GameLoop function / class calls itself repeatedly via setTimeout until all lives have been lost – then GameOver is called – and in each round it updates player positions, either from input or automation, checks collisions, checks if to update any pseudo-physics and then draws all players and platforms.

The game seems to run smoother in WebKit based browsers like Chrome or Safari, rather than Firefox for example.

Code:  https://github.com/bthj/Game-Engines—projects/tree/master/Game%20Engines%20-%20Project%201%20-%20Platformer%20game%20engine

 

Project 2:  Wireframe renderer

Implementing the 3d wireframe renderer was pretty much straightforward after reading through the given overview of the 3d transform process[1] for the second time and realizing that what’s needed is basically computing three matrixes, multiplying them together and using the resulting matrix to multiply with each vertex as a column vector, as shown in the given pseudocode.

The implementation consists of a HTML5 file, index.html, that includes jQuery Mobile for easy inclusion of a few UI widgets and then there is the wire frame rendering code in 3dWireframeRenderer.js

The function getCameraLoacationTransformMatrix implements what’s described in section 3.1.1 of the overview, Setting the camera location,

function getCameraLookTransformMatrix returns the matrix described in section 3.1.2, Pointing and orienting the camera,

and the projection matrix from section 3.2 comes from the function getPerspectiveTransformMatrix

The test meshes are in meshdata.js and I got them from http://threejs.org/editor/ and it’s export function.  One of the biggest difficulties was deciphering the faces array in the JSON export from there but then I found some documentation[2] on where the vertex indexes are located and the function getTriangleFaces does the job of extracting the vertices for each face.

When I had the function renderWireframe (basically like the given pseudocode) drawing vertices (I have them cover four pixels for clarity) and connecting them with lines, I had some difficulty finding a good combination of near and far values and camera Z position.  Adding sliders for those values in the UI helped, but, near clipping happens quite far away from the camera as it seems – I haven’t found a combination of near, far and camera Z position that allow the object to come near the camera without clipping, except, if I reverse the near and far values, for example set near to -300 and far to -10, and the camera Z position to 150, then the object (cube) renders happily close to the camera; is that a feature of the transformation matrixes or a bug in my implementation?  I don’t know…

The camera movement could be connected to the arrow / wasd keys and mouse but to see clearly the interplay between camera XYZ and the near and far planes is of most interest here so I’ll let those sliders do.

I tried getting the width and height from given FoV, near plane position and aspect ratio, as discussed in the overview and that didn’t play well with my UI so I abandoned that, but what I tried can be seen in the function getWidthAndHeightFromFOV.

Code:  https://github.com/bthj/Game-Engines—projects/tree/master/Game%20Engines%20-%20Project%202%20-%203d%20wireframe%20renderer

 

[1] “Overview of transforms used in rendering”  https://blog.itu.dk/MGAE-E2013/files/2013/09/transforms.pdf

[2] three.js JSON Model format 3.1:  https://github.com/mrdoob/three.js/wiki/JSON-Model-format-3.1

 

Project 3:  Pathfinding

For this project I started by reading an article on the web titled A* Pathfinding for Beginners for a text on how the algorithm proceeds but then I based the implementation pretty much verbosely on the pseudocode in the Wikipedia entry for the A* algorithm, along with supporting functions.

The implementation can be run by opening the index.html file in a recent browser (I’ve tried Chrome and Firefox) and pressing the Start button.  The chasing agent is represented by the letter C and the goal or target is represented by T.

When the target is moving the run can end without the target being reached when the open set becomes empty (line 145 in pathfinding.js), but the run can also end where the target has been reached.  It could be worth looking at the D* algorithm for this case.

The target moves randomly one step at a time horizontally, vertically or diagonally, except when it’s the next neighbor to the chasing agent (C), then it tries to choose a move that results in it not being the chaser’s next neighbor, which is not always possible (when the target is on the grid’s perimeter – see the last condition in the do…while loop at line 198).  It’s possible to have the target fixed in it’s starting position by unchecking the checkbox (Target (T) wanders and tries to avoid) in the interface.

Code:  https://github.com/bthj/Game-Engines—projects/tree/master/Game%20Engines%20-%20Project%203%20-%20Pathfinding

2 athugasemdir á “rotatengine.js

  1. Eu sou a favor da caça à multa. Devia acontecer todos os dias e a toda a hora. Se não comprem as leis, há que ser multado. É muito simples. Multas aos carros mal esooditnacas, multas ao lixo, graffiti, cartazes, tudo. Comecem por multar tudo e mais alguma coisa para ver se começa a haver algum civismo neste país.

Skildu eftir svar

Netfang þitt verður ekki birt. Nauðsynlegir reitir eru merktir *