Showing posts with label implementation issues. Show all posts
Showing posts with label implementation issues. Show all posts

Sunday, May 9, 2010

Oh hey, detecting and updating user presence is ridiculous. ( = pre-submission goals: update #2)

An annoying behind-the-scenes bug turned out, as I've learned after many hours of struggle today, to be far more frustrating and complicated than I could have imagined.

In my Users table in the database, I simply store a boolean, 'logged_in', by which I intend to record which players are currently using the app.  This does not mean whether they are logged into Facebook, since that status is likely unrelated to my app.  So, I define my logged_in boolean to mean whether the user is on either the index (home) page or the playgame.php page.

It's simple enough to ensure this boolean is marked true when the user loads either of these pages.  Detecting their leaving a page, however -- with the added requirements of updating all contingent information -- is unbelievably far more difficult.

Concerning the latter note, if a user leaves a game while it's in progress...
  • They should be marked 'logged_in' = false, since if they're navigating to one of the app pages, that page will restore that boolean to true.
  • Their 'current_game_id' and 'current_pid' variables must be set to null, to indicate they are no longer in that game.
  • If they were the last remaining player in that game, all turns pertaining to that game as well as the game's entry itself must be cleared from the Turns and Games tables, respectively.
  • If there are any other players left in that game, the 'num_players' value for that game must be set to the new correctly decremented value (and I don't want to just subtract 1, in case of race conditions, so I always want to check with how many players are still marked as involved in the game based on 'current_game_id' in the Users table).
  • The other players in the game should be checking for whether their fellow players have left, and must be informed of such dropouts.
 My original solution to detecting a player leaving the game page was to register the window.onunload event to make an AJAX POST to a php script that would update all appropriate things (see the list above).  This worked well enough in Firefox; I checked the results in the database, and Firebug showed me that the POST was indeed going through, despite the fact that the browser was navigating to another page.  However, I ended up discovering that the window.onunload event, or perhaps the POST, wasn't going through fully in Safari.  This led me to realize I should try an entirely different approach that would not rely on a browser event that may not have solid implementation in all browsers...

Many thanks are due here to John for helping me form new ideas for how to make this work.  Without going into the painful details and resulting unfortunate spaghetti-fication of my code (err..), the basic solution architecture is in three components:
  • The Users table now has a field called 'activity_time'.  Every 30 seconds, whether a user is on the home page or the gameplay page, an AJAX POST calls a php script to set this field to the MySQL CURRENT_TIMESTAMP.  So this is saying "user x is still here".
  • While on the gameplay page, the same script additionally checks for (a) any users marked with that 'current_game_id' but whose 'activity_time' is more than 30 seconds old, and (b) any users with one of the 'fb_id's registered (in a Javascript object stored by the page) as involved in that game, but with 'current_game_id' set to null.  [Note: (a) condition = those who have left the app by going to another page outside of it or closing the browser tab/window, and the cron job has not yet cleared up their data; see next bullet...  (b) condition = those who moved back to the app home page, which clears up their game data immediately, or those who have been cleared up already by the cron job.]  The id's of these "dropout" users are sent back to the page; the display of players in the game is updated to remove the dropouts, and a message is given to the user to advise them to return to the home page and start another game...(see below *).
  • There is now a cron job set up on the server to run every 5 minutes.  It calls another php script which retrieves all users whose activity time is more than 50 seconds old, removes any current game data they have, marks them as logged out, and either decreases the number of players in the game they had been in, or deletes that game entirely if it's now empty of players.
(*) Right now, there is no handling for updating the game state as it's stored in the ActionScript within the Flash app instance, nor does the page stop polling for the dropout players' turns.  As I see it, there are two options for where to go from here, regarding this issue:
  • Don't bother fixing the AS game state.  Just redirect the user automatically back to the home page.  This would make sense anyway for games that only had 2 players to start with, since playing alone is not as much fun.
  • Use the ExternalInterface class in AS to receive a notification from the page (via JS); update the game state accordingly; allow play to continue without the lost player(s).
Given how much trouble logout status has given me for many hours today, I'm inclined to go with the first option (or just let the user figure out that it doesn't work, and that they need to manually go back to the home page or leave the app).  It might turn out to be pretty quick to implement the second option, as long as there is still at least one player in the game, but I would rather turn my attention and remaining time towards a couple of the other goals on my pre-submission list, since I do think they are still important.

Finally, finally:


(I wonder how many Pandora hours I've used, out of my 40 hours given for the month, just from working today...)

Thursday, April 29, 2010

Considerations extracted from first (real-..)game chat

...with additional thoughts spurred from which...

Interface
  • show players (names, pics, association to colored piece)
  • display whose turn it is (and note "your turn" or "waiting for player __")
  • display your current speed (and others' speeds?)
  • and re: current speed - show a little compass of -x/+x and -y/+y directions

Instructions

How to interact with the interface:
  • click on circle to select move
  • gameplay is turn-based so you must wait for other players' moves
  • other players' circles are NOT clickable to you when it's not your turn

Gameplay:
  • goal is to be first around the track
  • how your speed is allowed to change for each turn, and that the game calculates this for you and shows you your available moves
  • when you go out of bounds, you lose every other turn for the duration of turns you are out of bounds
  • boundaries of track (both inner and outer) are considered in-bounds
  • cannot occupy same gridpoint as another player at the same time, but can occupy another player's previous gridpoint

Implementation stuff
  • handle out-of-bounds (lose every other turn)
  • handle off-the-grid
  • detect when a player crosses the start line again (i.e. the winner!)
  • don't let players be on the same point at the same time
  • display something differently about the optpos when it's out of bounds

Tuesday, April 27, 2010

The Facebook API battle/disaster night

I thought it would be fairly simple...


I had worked on a Facebook iframe application once before, and I remembered that the addition of requiring Facebook login and then being able to render XFBML components was not very complicated at all.  It was a matter of pasting in some code in a few different places, and magically, the page would request you to log in and add the application, and then it could show you your Facebook picture and name.  (By the way: FBML = Facebook Markup Language, and XFBML is the version you can use on off-site pages, i.e. your pages in an iframe, or on Connect app pages.)

Well, there I was, just over a year later.  I began delving into the wiki/documentation on authentication etc., and what I began to realize is that everything seemed to be in transition.  There was this new "graph API", and OAuth authentication, and a new Javascript API -- or at least, these all appear to be new, based on the look of the pages and what I could gather from the descriptions.

I really only wanted to be able do 3 things: require login and authentication of the app, pull/display users' names, and pull/display users' profile picture thumbnail.

Many long hours of confusion later, I had gone through stages something like this:
  1. using the wrong new stuff (a PHP API which I now think is supposed to be for Connect apps?);
  2. trying to use the old PHP library, cross-domain receiver file, XFBML, and iframe resizing... I don't even remember what didn't work in this combination, but some piece didn't;
  3. trying to combine the old PHP library and XFBML paste-in code with some of the newer stuff, I think? I don't even remember;
  4. attempting to manually implement the OAuth redirection cycle (things like obtaining a key and this and that), which actually almost worked...;
  5. deciding to give up on making this an iframe application that's actually within the Facebook chrome, and instead, switching it over to a Connect app, using the easy authentication/login via the new Javascript API and all of which is luckily still compatible with XFBML.
...wow.  It was a long, tiring, frustrating struggle.  Much of it was due to over-documentation, if you will, and a lack of clarity in terms of marking pages regarding at which level of API/platform transition the information and code on that page would still be relevant and functional.


And now for the bombardment of a list of links.  Here are some of the many Wiki pages/sections I tried to use to figure this out...

(Note: seems like they are really in transition currently - some of the links may not work or will give a message saying the content is moved/updated)


New (pages are in the theme of the new documentation)

Overview guide to apps (new)

Authentication (new)

Graph API (new)

JavaScript SDK (new)

Old REST API - apparently the precursor to the new Graph API


Old, but seems to still apply / be compatible with new stuff

XFBML (including tag list)


Old, and seems to not apply / not be compatible with new stuff

API (old?)

PHP (old?)

FB_RequireFeatures (old?) - for dynamically loading components of the JS API (via FeatureLoader.js.php)

Authorization and Authentication for Canvas Page Applications on Facebook - matches with the old(?) PHP library

Extended Permissions

Connect/Setting up your site - including XFBML rendering (but uses the FeatureLoader.js.php)

Wednesday, April 21, 2010

Multi: -player, -game, -track support

Comprehensibility of the following bullet-point lists is questionable, unless you're me and therefore intimately familiar with this project's code...

Multiplayer support:
  • Games support 1, 2, 3, or 4 players.  Having just one player right now makes no sense because there is no AI opponent.
  • Gameplay page polls (Javascript AJAX calls) database to discover additional players joining the game.
  • Player who initiated the game can decide to stop the polling and start the game; alternatively, the game will automatically be started if 4 players have joined (since that's the maximum it supports).
  • Once the game is to be started, it's set to in_play = true in the database, and the flashvars string is sent to the AS (including: game_id, track_num, pid, numPlayers...yeah for variable-name inconsistency!)
Multi-game support:
  • Can start a new game from the index page - game_id is sent through the querystring as -1 to indicate a new game should be started; PHP figures out the current highest game_id number and inserts a new game to the db with the next-highest id number.
  • Index page displays a list of games that have been initiated but are not yet in play (i.e. are open for more players to join) - these have not yet been closed by their organizer and still have fewer than 4 players.  One need simply click to join; game_id is passed in the querystring and retrieved in the PHP via the global $_GET variable.
  • The game_id is sent to AS through flashvars as mentioned above.
Multi-track support:
  • I made a MovieClip object called 'tracks'.  Each of 4 keyframes will eventually display a different track I've drawn, but right now they all show the same one.
  • When you are starting a new game from the index page, thumbnails of the 4 options for default tracks are shown, and you simply select one before you click the 'go' button to head to the playgame.php page.   The track number you've selected is submitted via a form POST.
  • For new games, the playgame.php page pulls the selected track number from the form POST and inserts it as one of the fields when adding the new game to the database.
  • For existing games (that you're joining), the page queries the database based on the game_id provided in the querystring and thereby pulls the track_num.
  • The track number is then passed to the AS as one of the flashvars.  Since this number refers to the keyframe of the instance of the 'tracks' MovieClip, I simply pass it as a parameter to display the correct track: realtrack.gotoAndStop(track_num).
  • NOTE: I've currently not implemented support for players drawing their own tracks... If I get to that, I'm not sure if I will be able to associate the track number to each game by just storing it as one of the attributes in the Games table.  My original database design includes a separate table for tracks, and I imagine storing custom tracks somehow would require this table, BUT, right now, with only my 4 possible default tracks it works just fine to have an id number (1 - 4) as an attribute for each game.
Well this post feels a bit disorganized and haphazard... I will try to post a screen-capture video of all this stuff soon.

Thursday, April 15, 2010

Non-retangular tracks will work after all

Dear Joe: I don't think I'm capable of writing a short post.

So you know how in the past, the "track" has always been two concentric rectangles?  That's because I was simply drawing it as a Shape object.  To be able to call hitTestPoint on it (to check whether players' pieces were inside the track), I added a fill to the track space, but set alpha = 0 for those pixels so they would be transparent but still register as hits.

Well, no one wants to play this game on a rectangular track all the time.  So it's finally time to make more complex tracks work.  I didn't want to try to draw a curving track by piecing together arcs using the drawing API, so instead I made a new MovieClip object to add to the library.  I called it 'tracks' and am thinking I'll make several tracks, each one on a keyframe.  The user will somehow be able to select one, and then I'll just call gotoAndStop(frame#) on the one instance of the tracks object, and add it to the main scene.

For now I just drew one track using the pen tool and smoothing out the corner joints (vertices) between line segments.  If you go into the menu (Modify -> Shape -> Advanced Smooth...) you find a function that'll create curvature-editing handles for the vertices.  It's not exactly what I was expecting based on experience with Illustrator, but it came out decent enough.  Luckily, I was able to add a transparent fill within the track area (just using the fill tool), just like I'd done programmatically with the rectangle track.  And the bounds testing using hitTestPoint works = one hurdle easily cleared.

[Next steps: multiple tracks to choose from; users drawing their own tracks...!]

Tuesday, March 23, 2010

Storing a Turn: From Actionscript to the Database (Plan)

After deciding last night might be a good time to do something useful for my project, I chose to tackle an important feature component of my game that I had yet to really look into: making it multiplayer across client machines.  In other words, I needed to figure out how to:
  • take the occurrence of one player's turn (which happens on the Flash movie on one player's browser), 
  • send the critical information (which player and their new position on the grid) to the database on the server, 
  • and update the display of that player on all of the other players' Flash movies.
Since PHP is my avenue to the database, I set out to learn how to send information between Actionscript and PHP.  I stumbled on a forum thread that includes enough code to seemingly walk me through the necessary steps for packaging up Actionscript variables and sending an HTTP POST request to a PHP script (which can then insert values into the database).

In addition, the thread mentions that you can attach a callback function which will handle the event of the completion of the request--i.e. once the data has been loaded from the requested URL, that function is called and you can access the returned data.  So in the PHP I'll check on the success of the database insertion and send that result back (which I believe is just via 'echo' in PHP... wow I'm rusty on PHP).

I intended to draw a higher-level diagram of how this would all work, but I ended up writing in what is almost entirely correct code (as opposed to pseudocode or less).  I have some explanatory side notes written in, and arrows to show the overall informational flow.


*Important note*  I realized that this plan encompasses only the communication between one instance of the Flash game (on one client browser) and the database.  It does not cover the implementation of updating multiple players' instances of the same game on different clients, but it is the first step towards that.


Anyway here's the diagram.  (As usual, click to see in full size.)  I have a propensity for hand-drawing/writing stuff these days, it seems.

Thursday, March 18, 2010

Meeting with Dr. Nimeroff: Database structure and linking multiple players

I met with my adviser, Dr. Nimeroff, for a bit the other day and we mainly discussed two related points.  Since it's been awhile since I've tried to design a database, we first talked over my ER diagram.  He didn't see any major potential issues with it right off the bat, so that was a good start.  We focused on the 'player_group' relation between the 'games' and 'users' entities.  I had not been sure whether it would be necessary to store player state information, like the x- and y-position, for a running game--in my newness to Flash/Actionscript, I'd been thinking something like that could be stored in Actionscript variables.  Dr. Nimeroff explained, though, that the Flash swf and associated Actionscript are run locally on each user's browser, so when values and visual elements change for one player, they aren't automatically updated for other players.  The key here is that whatever information is needed to update players' states on each others' "copies" of the swf and of variable values in the code must be saved into the database (since that, of course, is stored on the server) and then retrieved by calls from the other players' browsers to receive the new state.  Thus, it was a good thing I included such state information in my ER design.

Along these lines, I then asked about an issue that has been a "hole" in my mental plan of implementation since the beginning: how do other players' local machines find out that an update has been made to the database and take appropriate action to update their own copy of the game state in the code and swf?  I do want the game to be real-time, though it is turn-based, which makes it far easier than having to support multiple players doing things at the same time.  The only thing I could think of was polling; the Actionscript would just ping the database every fixed interval of time to look for a change and pull the new info if necessary.  I had also wondered whether the reverse idea would be feasible: could the database notify the game instances when an update was ready?  Dr. Nimeroff said that the former (games-poll-database) method was definitely the way to go about it.  Since the game is turn-based, it's not creating a constant stream of updates that need to be passed around; thus, a polling request every couple of seconds or so would not be a strain on the server.  Plus, the amount of data to be transferred per request is very little.  Finally, this is much simpler than the database trying to keep track of which instance to notify, where to send the notification, and the like.  This conclusion was very exciting for me, as I am no longer in the dark about a doable and sensible approach the implementation of multiplayer support.  And I think I might even know at a high level how to go about it.  Yay!

Tuesday, March 16, 2010

Discussion with Dad, part 2: Detecting boundaries and out-of-bounds moves

I also spoke in a more high-level sense with my dad about an important issue that I need to solve programmatically via Flash and Actionscript: the program's "awareness" of boundaries.  Here are some methods that I or we came up with:  (Note that I may not have yet researched the feasibility of each.)
  • Store a 2D array of booleans.  Each cell corresponds to a grid point (i.e. potential position) and the boolean simply states whether the point is inside (true) or outside (false) the track boundaries.  This takes initial overhead to create but makes detection of out-of-bounds moves a simple array-access call.  I could create such arrays manually for tracks I draw that will be provided as pre-made tracks; the bigger issue is how to compute this array for user-drawn tracks.  My dad's solution to that is to allow users to draw the track only as a series of connected straight line segments; as each segment is created, the its slope (change in x / change in y, in grid-points) can be used to set the booleans for nearby grid points.  [This corresponds to the left-hand part of the scanned diagram below.]
  • Check each player move for bounds-crossing.  An idea I had already had is for each time a player selects their next move, a line will be "drawn" (programmatically and hopefully invisibly) from the previous position to the new one.  Then, check if this line intersects with (crosses) a track boundary.  I'm not exactly sure how such an intersection check would be accomplished in Actionscript, though I tried to look around a bit for some methods (see the resource links post)...  [This corresponds to the right-hand side of the diagram below.]
  • Use the intrinsic ability of Flash to "know" which area is inside and outside a shape.  This is not as crazy as it sounds.  My dad explained that such data must be stored somehow; the simplest justifying example is that enclosing bounds (i.e. a shape) can be filled with a color.  Since I had no clue how I might access this stored data, I realized maybe I could take the color-filling ability at face value: maybe I can just fill the space outside the outer boundary and inside the inner boundary with a color, and check pixel colors to see if a particular move is in bounds or not.  Again, I figure this can be accomplished with Actionscript; the solution could range from not-so-elegant to rather-hackerish.  Anyway, I'll have to look into it.  [This only corresponds to diagrams in my head, so far.]