Showing posts with label problem. Show all posts
Showing posts with label problem. Show all posts

Wednesday, October 22, 2008

Lock's Quest Recap

This is sort of a game review, but also a discussion about interface design, and the nature of fun in games. I recently purchased Lock's Quest, which was the best Strategy game at E3, which for a DS title, is pretty impressive. It's developers also put out Drawn to Life, a game that I wanted, but never got around to purchasing. Basically, you're a special boy in a war...blah blah blah, the story isn't really that important, but the game itself is really involving. 


You have so build walls and turrets to fend off increasingly large and tough armies of clockwork robots. That in and of itself sold me, but the DS's touchscreen is really well implemented in both combat and repairing damaged structures. Depending on what you're trying to do, there's an associated task (pulling a lever, spinning a gear, etc) that makes the action you're attempting go faster, or more effective. While this sounds kind of hackneyed and repetitive, they're mixed up nicely, and you don't just sit around for 10 minutes doing the same thing over and over again.

I'm also really impressed with how they set the flow of the game up. After a few rounds with your defenses, you have an impenetrable death-fortress, and you're able to handle even the most vicious onslaughts. Then, the game tells you that you have to go grab an objective all the way on the other side of the map. It's frustrating, yes, but it breaks the whole build-repair-fight cycle, which is nice. It's also worth noting that there's few things more awesome than watching wave after waves of bad guys crash on the rocky cliffs of your defenses.

One thing is infuriating though. The screen doesn't zoom out, and there's a fixed speed to the camera, so panning from one wall to another can sometimes take precious seconds. This in and of itself is not too bad, since (if you're like me) you can set up relatively smaller, close defenses. However, when you pan to a location, and then tap (which tells your character to move there), the AI that keeps the main character from running aimlessly into a tree is a little bit lacking. So far, I have lost a solid number of turrets, and even a level or two, just because there was a rock or tree or bit of something in the way, and the flax-haired hero did nothing except struggle against the properties of matter until I realized and gave him an easier location to get to (after a while, you get used to tapping out smaller, shorter paths).

With that behind me, I do have a few more good things to say about this game. Despite the "ehh" story, the game has a good length to it. I thoroughly enjoy the game mechanics that are in place, and was worried that with all the cool stuff in it, that the levels would be cut tragically short, leaving me wanting more, much like when you when you visit home, and only get a single strip of bacon, because that's "healthier." Don't worry, this game has platters of bacon. I've been playing it for about two solid weeks now, mostly during my commute and at home and I think I'm only 2/3 of the way through it. 

Also, the difficulty is really well done. While I didn't like that there wasn't a standard dial-a-difficulty, which would be pretty easy to do with this game, I was able to clear most of the levels on the first try, though a good number of those were nail-biters, and a couple of them required a do-over. The increases in challenge over time are well-paced. I never felt too bored, and when I was right on the edge, something new popped up. Also, there's a fun little seige mini-game which would be right at home as a flash game.

Monday, July 28, 2008

Variable Scope Issues

Again, here's a new link to my latest project. http://www.cs.drexel.edu/~asc38/Projects/CdlC/
I think it's actually pretty fun, so I hope you try it out.

The only major issue left to tackle is the high score board. When the game ends, you can submit your score to the online scoreboard (I'm currently in first place, go figure.) It was a chance for me to play around with flash's internet communication abilities. It works pretty decently as well, if you ask me. The problem is that, for some reason, the scoreboard only shows up the first time you play it (per page refresh). What that means is that if you press the "Play again" button, play the game, end the game, and submit your score, you won't see the scoreboard. I'm completely scoobied as to why that is. The code to update the scoreboard is as such:

trace(event.target.data);
htmltext = event.target.data;
scoreBox.htmlText = htmltext;

If you're not familiar with flash, trace is a command that outputs things to a special "output" window. Therefore, the event.target.data variable should be shown on my screen. The problem is that despite the fact that I do get the correct text outputted to me by the trace call, the scoreBox.htmlText doesn't reflect what it was given on anything other than the first time through the game. I had a similar issue (in fact it was the only real major "bug" in the first iteration) with the images from the last scoop being present on replays as well, and that was fixed by making sure that everything was reset properly at the appropriate time.

My guess is that this is a variable scoping issue, partially because that was the issue the first time, and partially because Flash's scoping is about as confusing as watching Memento when you're tripping acid. As far as I can tell, variables instantiated within a frame are scoped globally, unless they're within a loop or function. However, commands, or anything else for that matter, only apply at that specific frame. This kinda makes sense. You might want to use a variable you defined somewhere else in the program, and you don't want all of your code executing at once. The issue here is, when are objects (like the scoreBox) that are defined in the scene, not in the code, created? Are they global? Can I change their values before they're visible? I'm still trying to figure it out, so if anyone has any suggestions, feel free to leave them in the comments.

As far as I can tell, it's only used for debugging, as my experiences with the actual Flash debugger were about as pleasant as shaving with a rusty butter knife.

Thursday, April 17, 2008

Gettin Things Done

I went to a meeting for my university's local game dev group yesterday. The discussed topic was "What To Do Break Into The Game Industry." There were some helpful hints as to languages, networking events and the like, but one point that the speakers drove home (and I felt was VERY important) was this:

Make Games

It's so simple, but a lot of people, and not just those in the game development field, have a problem with it. Not just games, but all sorts of programs. In school, we usually just make some throwaway scripts that we use once for an assigment, and never look at again. Knowing how to do stuff is very important. Actually doing stuff, that's a whole nother level. If you go into an interview and say "I know how to do X,Y, and Z," they might be relatively impressed. However, if you can say "I did A, using X and Y, but I didn't get a chance to implement Z yet," that is umpteen times better than the first one. Companies don't care if you know how to do stuff. I know the basics of how to play baseball, that doesn't mean that the Phillies manager is going to be beating my door down trying to get me to join the team.

The problem with this is: making stuff can be tedious, and boring. For every cool bit, there are probably ten times that much of boring stuff that you have to slog through before you get there. It's hard to strike a balance, especially if you're like me and hate doing work in your free time. It's boring, but everything's boring if you do it enough. Try to add new stuff to the boring bits wherever possible, and you'll be okay.

Most importantly, though, do stuff, don't just learn stuff.

Monday, February 25, 2008

Playlist Loading/Shuffling

Sorry it's been so long since my last post. I took a trip up to New York for an OpenSocial Hackathon (which I'll discuss in a later post,) but I just had this thought mulling around my head and felt like writing it down.

I probably use my media player (WMP, Songbird, AmaroK, etc) more than any other program on my computer. No matter what I'm doing (coding, web-surfing, doc writing, or all three,) I'm usually listening to music. I'll pick a playlist, either from my list of pre-made playlists, or just throw one together at the drop of a hat. However, I really hate how most modern shuffles absolutely fail at "shuffling" my songs. On my n800, GP2X, and ipod before that, I could tell that there was no list order, but that the player literally just selected a random song from the list, and played it. Yeah, it's fast, but it's lazy, and kind of infuriating. A few days ago, on WMP, it actually played the same song twice. As far as randomness goes, that's technically random, but I don't like random, I want shuffled.

When you're playing a card game, you don't reshuffle the deck every time someone puts a card down (though that could really screw up your magician friend's magic trick.) No, you wait until the deck has been fully uncovered (or the hand ends.) 

Along with that, even though WMP loads a playlist, it "shuffles" it, but it's pretty lazy as well. That's why when the playlist ends, I coudl theoretically listen to the same song twice. Even along with that, though, sometimes it'll get into blocks where I hear all of an artist's songs right in a row, which is frustrating as well.

I don't have any code at the moment, but it would really be nice if there was a good shuffling algorithm that made sure that artists' songs were kept spread out, prevented playing the same song close to itself, and, in general, made my most commonly performed task a little bit nicer.

Friday, December 28, 2007

Adding Hidden Fields Programmatically With C#

Sorry it's taken so long to get another post up. The holidays, and the fact that I have a major project due tuesday, have been keeping me from my beloved blogzorz.

This is just something I ran across in my project, it stumped me for about 10 minutes, so I did a search for it, and nothing I saw explained it adequately, or even loaded properly. So here's what I came up with.

I need to add several hidden fields to a form, that contain data needed on the receiving end of a POST request I'll be sending. The values are not static, and need to be a) pulled from a database, and b) used in a crypto method, so obviously just posting HTML input tags just wouldn't cut it. So, I tried having the input tags, but couldn't access them from the codebehind. There are two easy ways to fix this.

1) The CodeBehind Way

In the codebehind, create a new HiddenField:

Hiddenfield field = new HiddenField();

Give it a value:

field.Value = value;

...and set it's ID

field.ID = idValue;

Then, all you have to do is add it to your form:

form.Controls.Add(field);

And it's there! One interesting thing to note, though, is that the ID value you give the HiddenField will be used in the HTML as both the id attribute, and the name attribute. So, if the name attribute is important to your reciever's code (which it is in my case,) make sure you set the ID properly.

2) The Even Easier HTML Way

Add runat="server" to the input tag. I had a face-palm moment when I realized this would work, but it does. The caveat with this method, though, is you have to give it an id attribute as well, or else you won't be able to access it from the codebehind. To set the value using this method, make sure that the HTML is like so:



Then you can edit it in the codebehind as such:

nametocodebehind.Value = hiddenvalue;

And that's it! To make up for not posting last week, I'll be posting again this week, most likely about jewelry and user experience.

Friday, December 14, 2007

URL Sanitization and Picnik

This is a much shorter post than the others have been, but I don't think that's going to be too terrible. ;-P

Anyways, I'm also working on integration with our product with Picnik, and just recently resolved an issue with them. Our images are (or will be) hosted with Amazon's S3 service (which is wicked sweet, if you know how to use it,) and we use secure URLs to access them, along with all the parameters that amazon requires to call a photo (securely.) They fixed the secure URL issue, but for some reason, the photos still would not load in. It turned out that the parameters in the Amazon URL were the problem. They needed to be sanitized (i.e. all "="s became %3D, etc. I found the conversions on this website.) before they'd work. After doing that, they worked fine. One important thing to note, though, is that if I write anything to generate URLs for S3-based images, there should be another one for creating the "editing" url, complete with the picnik url and sanitized S3 URL. Good thing to remember, and it was a reminder that little things like that really have to be watched for, since they happen to me far more often then I'd like to say.

Wednesday, November 28, 2007

OpenSocial Activity Posting

NOTE: This code and post was written for an older version of Opensocial. I make no guarantees as to it's validity in later versions.

There are four APIs to opensocial: Javascript, Activities, People, and Persistence. The last three haven't been released yet, but the Javascript one already implements some of the features that they will support. For example. the People API will let you retrieve a specific person, or a specific person's friends. That can already be done (mostly, you can't get a person by ID yet) in the Javascript API. I ran through what could be done with people pretty quickly, and was able to get a demo up using persistence as well, but activities have been puzzling me.


The Activities Data API describes how you will be able to create, retrive, update, and delete activities. That sounds sweet. Except for the fact that right now, with the Javascript API, the only thing you can do is create activities. Even doing that is kind of confusing, so I'm going to go through what I've learned so far.

Before you can even think about creating an event, you have to create a stream. You do this with opensocial.newStream. The first parameter, folder, has apparently already been deprecated, so I've just been putting "null" for it. Title, the second parameter, is apparently the title of the stream (real big surprise.) I've done some tests, and if you use newStream with the title of an already existing stream, it still creates a new stream. I'm not sure what it does to the old stream, but activities that have already been posted to a person's update feed aren't removed. The tests were part of a demo app I'm working on, so they're not in their own test apps. Once I get them seperated, I'll post a link to them. Finally, you can post a map of optional parameters. Right now, the only two fields that interest me are USER_ID, and FAVICON_URL. I haven't tested FAVICON_URL yet, to see how well it works, but USER_ID got me really excited. When I was first working with the activities, I thought that I could only post updates to my own update feed (which is sort of redundant, but it is the default if no USER_ID is specified.) All you have to do is specify the USER_ID, and any activities posted to that stream will go on that user's update feed. SO, here's the line of code that I use to create my stream.


var activitystream = opensocial.newStream(null, title, { "USER_ID": friendId });
"title" is a variable containing whatever I want the stream to be titled. "friendId" contains the id of the friend whose feed the activities will be posted to.


Alright then, the stream is set up. Now you get to create the event. That's accomplished with opensocial.newActivity. It has three parameters as well. The first one, stream, is the stream variable you just set up. The second, title, is the most important. It is what will show up on the update feed. Also, since the optional parameters don't seem to be doing jack at the moment, it's ALL the person who recieves this activity will see. Here's how you set up the activity.


var activity = opensocial.newActivity(activitystream, text_to_display, null)

I just leave opt_params as null, since they're pretty useless now.


Almost done! You've set up the stream and the activity, and even told the activity what stream it's going to be posted to. Now, all you have to do is let it loose. This is done using the opensocial.requestCreateActivity method. It has, beleive it or not, THREE PARAMETERS. The first is the activty variable, which has the stream variable, which swallowed the fly...etc. The second is the "priority" of the posting. There are only two options (at least at the moment), opensocial.CreateActivityPriority.HIGH, and opensocial.CreateActivityPriority.LOW. HIGH means that if the stream you wrote to doesn't exist, the activity will still be posted. If you choose LOW, and the stream doesn't exist, the activity will not be posted. Supposedly, there is a chance that using HIGH will navigate away from the current page (your opensocial gadget,) but I've never had that happen to me, and I've only been using HIGH. The third parameter is a function to be called when the activity has been posted. It's optional, but I've been using it to verify that the operation completed. Here's the last line of code you need.


opensocial.requestCreateActivity(activity, opensocial.CreateActivityPriority.HIGH, callbackFunction);


There you have it, the longest explanation of three lines of code ever. ;-P At least now you can post updates to your friend's update feeds. One other little caveat I should mention, if the title of the activity is identical to another activity in the same stream, it will not be re-posted. My guess is that changing the opt_params might allow this to happen, but I haven't tested it yet.

As far as programmatically accessing streams/activities, I'm totally scoobied at the moment. After I post this, I'm going to check the DataRequest methods, and see how much I can/can't do with them, but for now, I'll leave you with being able to post activities. Catch youse later.

Monday, November 26, 2007

OpenSocial Browser Incompatability

NOTE: This code and post was written for an older version of Opensocial. I make no guarantees as to it's validity in later versions.

Just a quick note: I'm going to set a goal for myself to do at least one blog post per week. It will be of a decent length, and not filler in any way, shape, or form. One of my biggest dislikes of the blogosphere is that people post the most useless stuff. I'm going to do my best to avoid it, but if I start sliding, someone let me know, please.


Back to the topic at hand...


I've been working with Google's new OpenSocial Framework recently (
more info), which is a social networking framework that can be impelemented by social networking sites to provide cross-platform support for developers, making things a lot easier for third-party social app developers. There's one big glitch, though. It doesn't work on all browsers. I did some initial research on the topic, and was asked by Google to open a group dedicated to finding and documenting these differences (look here). The basic jist is this: Firefox and Opera work fine, IE and Safari don't. Safari asks for access to something in google's domain (which users/developers don't have access too,) and IE has something going on with it's requests.


In all the attempts that I made, any data request made from IE came back with a 401 Unauthorized Error. So I looked at the request made (using
Fiddler, which is a great piece of software). So here's what I found in a request for the information about the viewer of a page.


IE Request:

POST /46/o/api/json HTTP/1.1
Accept: */*
Accept-Language: en-us
Referer:
http://64b409ht-a.gmodules.com/ig/ifr?url=http://www.cs.drexel.edu/~asc38/Google/Test6.xml&parent=http://sandbox.orkut.com&lang=en-US&country=US&synd=orkut&mode=canvas&nocache=2147483647&mid=0&h=200#st=AFinprSFNk0cx-EYLjFu4KnGC8ErtahjWjnpbuHHWFEYTpx2pp2zBPW-N1gC-xtto2aB3gq7RW_B4wcDS1GzSkXNRoJrD0ScvjxAEhcmWl0_LvGe1TyJDm0&gadgetId=06080089800194424967&gadgetViewer=09795457263253596479&gadgetOwner=09795457263253596479&nocache=2147483647
Content-Type: application/x-www-form-urlencoded;charset=utf-8
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.5.20706; .NET CLR 3.0.590)
Host: 64b409ht-a.gmodules.com
Content-Length: 190
Proxy-Connection: Keep-Alive
Pragma: no-cache
req=%5B%7B%22key%22%3A%22viewer%22%2C%22request%22%3A%7B%22type%22%3A%22FETCH_PERSON%22%2C%22parameters%22%3A%7B%22id%22%3A%22VIEWER%22%2C%22profileDetail%22%3A%22basic%22%7D%7D%7D%5D&out=js


Looks pretty standard, huh? The body has a value named req, which appears to have some of the request data. There's also a decent bit in the referrer header as well. For some reason, however, this gets the 401 error. Let's check out the Firefox request, and see what the difference might be.


Firefox Request:
POST /46/o/api/json HTTP/1.1
Host: 64b409ht-a.gmodules.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Proxy-Connection: keep-alive
Content-Type: application/x-www-form-urlencoded;charset=utf-8
Referer: http://64b409ht-a.gmodules.com/ig/ifr?url=http://www.cs.drexel.edu/~asc38/Google/Test6.xml&parent=http://sandbox.orkut.com&lang=en-US&country=US&synd=orkut&mode=canvas&nocache=2147483647&mid=0&h=200
Content-Length: 313
Pragma: no-cache
Cache-Control: no-cache
req=%5B%7B%22key%22%3A%22viewer%22%2C%22request%22%3A%7B%22type%22%3A%22FETCH_PERSON%22%2C%22parameters%22%3A%7B%22id%22%3A%22VIEWER%22%2C%22profileDetail%22%3A%22basic%22%7D%7D%7D%5D&st=AFinprR418rXG6TALrKsP6Ad_U1xE3E7z2_F22lrqaGoNvFN2NpWE7zB6-nqW69Zy9W-sgP8QNvSu7aTXe_ZfeSe-vBNjAvJa_BUohr6C3_l89naEvApO9s&out=js


Notice a difference? The Firefox has a lot more detail in the req value, and a bit less in the Referer. Here's a little summary of what's in where.


As far as the referers go, both browsers have the same address, url, parent, lang, country, synd, mode, nocache, and mid parameters. In fact, after mid, the firefox referer value stops. IE just keeps going, with a "#" seperator, instead of a "&". Usually, "#"s are used as an anchor to a link on the page, but that doesn't make sense on two accounts. First, this is a referer to a page, and second, because the anchor apparently has a value too. Other than the "#" sign, it appears to be assigning some sort of key value to the variable "st". Then, it even goes on to declare the value of gadgetId, gadgetViewer, gadgetOwner, and another nocache.


The req value is also a very similar story. IE and Firefox have an identical value, except that IE doesn't include the st parameter, which Firefox does. The st values are different, but I'm guessing that st stands for "state", which one would expect to change. Would the state cause a 401 error? Maybe, only Google knows.


One other interesting thing to note. In the accept header, IE just has "*/*" listed, which I assume means that it accepts all formats. That's nice, but Firefox has the following listed in the accept header "text/xml, application/xml, application/xhtml+xml, text/html;q=0.9, text/plain;q=0.8, image/png" (spaces added after commas by me).


I don't have any solid answers, but here's my hypothesis: the "anchor" value in the referer header of the IE request is what's doing it in. Somehow, that adds something to the request that is a no-go for OpenSocial, causing it to error out.