Windows 8: Pinning Documents to the Start Page #2

Jan 10 2013

Send to Kindle

In a post last week, I gave a kind of convoluted solution to pinning a document to the Windows 8 Start Page. Jesse Freeman just pointed me to a Windows 8 app that does the same thing in a bit more of an elegant way: Tile A File. You simply start the app, browse to a file you want to pin, and tell it to create a Start Page tile. You can opt to use the default icon it picks, or choose a custom tile image. Nice solution.

Send to Kindle

One response so far

Windows 8: Pinning Documents to the Start Page

Jan 06 2013

Send to Kindle

Before diving into all the stuff below (which still might be useful in some cases) you might want to look at this post: http://www.bit-101.com/blog/?p=3657

If you’ve read past the post title and into this text, I’m going to assume you have some experience or at least some interest in Windows 8. Therefore you know that there’s a Start page with tiles of various applications installed on your system. You can rearrange these, remove and re-add them, and in some cases resize them. A lesser known fact is the ability to pin folders to the Start page – just right click the folder in Explorer and you’ll see a “Pin to Start” menu item.

What seemed to be missing for me though, was the ability to add documents to the Start page. For example, I have an Excel spreadsheet where I log all my running, with various charts, weekly and monthly tallies and other analysis all baked into it. I use it almost every day, so I thought it’d be nice to have it pinned to the Start page to bring it up as fast as possible. There doesn’t seem to be any automatic way to do this, but I did figure out a little trick. It’s not quite a single-click solution, but for those few documents you use all the time, it’s worth the minute or less that it takes to set up the one time. You could also probably create some kind of script or utility to do this, but not sure it’s worth the extra effort. Anyway, here’s what you do:

1. From Explorer, right click on the document you want to pin and choose “Create Shortcut”. This will create a new file next to the original, which is an alias pointing to the document.

2. Now you want to copy this shortcut into the following folder:

C:\ProgramData\Microsoft\Windows\Start Menu\Programs

It’s probably going to tell you that you need administrator privileges to paste it there. You can just click continue to acknowledge this, assuming you do have such privileges.

3. You may want to rename the file. By default it will be something like “Keith Running Log.xls – Shortcut”. This is what will show up on your Start page under the tile, so if  you want, change it to something like “Keith Running Log”.

4. Now go to the Start page. You won’t see the tile there, but start typing the name of the file and it should quickly filter it out. Now right click it and choose “Pin to Start” from the App Bar. Bingo! A pinned document. (You’ll see I got lazy and didn’t even rename it.)

Note that this is not limited to MS Office docs. As far as I can tell, any document with a registered extension that will open in some application can have this method applied.

I’d love to see a Windows update that makes this a bit more straightforward, but at least it’s possible.

 

Send to Kindle

8 responses so far

Game in Progress: Infiltration

Jan 04 2013

Send to Kindle

I just wanted to share a little bit about the game I’m currently in the process of creating. It will be a Windows 8 game, called “Infiltration”. The game play, as well as the visual style, is very much a homage to the arcade classic Gravitar, but it is far from an exact copy. The concept is that you have to infiltrate this alien world, fly through various barriers and tunnels and capture one or more targets. I guess I’ll make up a story of what these targets represent – information, energy crystals, or whatever. Anyway, once you grab all the targets, while avoiding being shot, taking out the guns that are shooting you, and keeping track of your fuel, the exit will appear and you fly into it to complete the level. Here are a few screenshots of some of the levels:

  

The controls are basically what you would find in Gravitar or Asteroids: turn left/right, thrust, shoot, with some friction so if you are drifting left or right you will come to a stop fairly soon. The world of the game has basic one dimensional gravity, i.e. your ship is pulled down so you need to regularly use some upward thrust to keep from crashing. Thrusting of course uses fuel and when you run out of fuel, you’re gonna crash. Most of the levels have fuel pods you can pick up to replenish your reserves.

A Word about Gravitar

Gravitar is one of my favorite old school video games. This is not to say that it was my favorite back in the day. I remember it in the arcades, but I never played it that much. Why? Because it was freaking HARD! Now I play it on MAME, which doesn’t waste my hard-earned quarters (worth a lot more back in the early 80′s), but I’m still not even close to beating all the worlds in the first universe. If you want to see for yourself how tough it is, try the online version here: http://my.ign.com/atari/gravitar.

Beyond the visual style and basic game play (fly, shoot, fuel, get out), I did want to capture a bit of that difficulty in Infiltration. So most of the levels are pretty damn hard. I imagine some casual users might consider a few of them impossible. But 1. I will have completed every level personally, and 2. I still don’t think it’s as hard as Gravitar.

If you are interested in Gravitar, you need to check out Dan Coogan’s Gravitar site. Seriously, this is virtual shrine to the game. There you can find screenshots and walkthroughs of every level, interviews with the creators, scans of the original manuals, flyers, ads, etc. There is even 350+ scanned pages of the original Gravitar design binder – original sketches, plans, meeting minutes, office correspondence about the game, cabinet specs, etc. An amazing resource to see what went into making a game like that back in the day.

Designing Levels

It became obvious to me very early on that if I was going to be designing a bunch of levels, doing it by plugging numerical coordinates into some kind of text document, loading the level, seeing what it looked like, tweaking the values and checking again, etc. was going to be very painful. So I set about making a graphical level editor for the game. This was also done as a Windows 8 app and became a major side project for a few weeks. I can now draw out a full level, place, move, and delete any game items, all with a full undo/redo stack, and load and save levels as JSON. It’s got a grid you can toggle on/off as well at toggle snap-to-grid, and inputting of level metadata. I’m pretty proud of it. Here’s what it looks like in action:

The next pain point was after creating a level, I had to add that level to the game project and compile the game. And then recompile the game every time I made a change. So I added a feature in the game itself to be able to load custom external (not compiled in) levels from the file system. At this point, I don’t even need to have Visual Studio open anymore. I create the levels in the editor and test them in the live game. Tweak the level, save, reload the level in the game.

This has worked out so well that I’ve decided to leave the external level feature in the game itself, and release the editor as a public app as well. So, when this is finally all completed, people will be able to create their own levels, play them, share them with friends, etc. Maybe I could even get some kind of best level contest going.

Current Progress

As of this writing, I have 23 levels done. I plan to have 30 in total. The first few are pretty easy tutorial-type levels. It gets tough pretty quickly after that though. I think I’m going to check out the try/buy functionality for this game, releasing a trial version with a selection of levels, and a full version with all levels plus the ability to load custom levels. The editor would be free, but only useful if you have the full version of the game. The trial may have ads as well. Not looking to get rich here, but I never signed my vow of poverty either.

I’ve been working on this since the beginning of October. So it’s been a couple of months and I’m itching to be done with it. I think there is little, if any, coding left to be done, just level creation, which I hope to wrap up by this weekend. Then I’ll probably need to tweak and rearrange the levels a bit to make them flow. Hopefully you’ll see this in the store by the middle of the month, if all goes right.

Send to Kindle

4 responses so far

2012 in Review

Dec 31 2012

Send to Kindle

Following a tradition several years in the running, I bring you my personal retrospective into 2012 and a glimpse into the new year.

In fact, 2012 followed much the same pattern as 2011 – some interesting stuff in the start of the year, a long period of just kind of being bored with everything, and then finding something to be excited about as the year drew to a close.

As 2011 ended, I was starting to get more seriously into JavaScript and web development. In early 2012 I posted a few opinionated opinions on object creation in JavaScript, which sparked some good conversation. I followed these up with a couple of articles on the same subject on the Adobe Developer Center.

In April I went to Beyond Tellerand – Play, a creative/development conference in Cologne, Germany. I revived one of my most popular talks, Playing With Chaos, for this conference, redoing all the examples in JavaScript. It went over amazingly well. The talk is always really well received. After that, I had the idea to turn the talk into a self published book and got a good start on it. But that kind of fizzled out after a couple of months. Perhaps I’ll revive it some time in the new year. You can actually watch the whole talk at the BT Play site, along with the other sessions.

It turned out that BT Play was the only speaking gig I did all year – the least amount of speaking I’ve done since I’ve started. I did have a couple of other opportunities to speak, but have not been super interested in doing so, to be honest. There are few if any “Flash conferences” around anymore, and even if there were, I’m not really doing any Flash these days. I don’t feel expert enough to try to get into the JavaScript conference speaking circuit. I probably could do more stuff like the chaos talk, which would go over well in any kind of creative type situation, but the impetus just wasn’t there for some reason. I guess another part of it is that the Flash conferences had a certain group of people you knew were going to show up. A large part of the pull to speak at these was the hooking up with friends from around the world and hanging out with them. I do miss that.

In June, my coworker and friend, Todd Anderson, and I went down to Austin for the TXJS conference, as attendees. It was very odd not knowing anyone else at the conference, and I’ll admit it, not having people coming up to me saying they read my books, blog, used my components, etc. It was also around this time that I started to get a bit bored with JavaScript. This statement needs a lot of clarification. I don’t have any problem with the language itself or what it can do. And at first, I was pretty excited about all the stuff happening in the community – so many new libraries and frameworks coming out all the time. But this latter part is what eventually got me bored with it. Too many frameworks, too many opinions. and everyone in your face telling you the RIGHT way to do things. I guess I was a bit guilty of this myself earlier in the year with my object creation posts. But I just kind of got tired of all the king-of-the-hill playing that’s going on in web development this last year or so. I got too caught up in the “how to” part and wasn’t really MAKING anything.

So you might have noticed that from June to August of this year I went pretty dark. Honestly I wasn’t even doing anything blogworthy. A bit of a technology sabbatical, covered well enough in this post. Also mentioned in that post is that Windows 8 programming is what pulled me back into activity. I now have two apps in the Windows 8 Store and am very close to having my next one ready for submission.

If it’s not obvious already, I LOVE Windows 8 programming. Everything I’ve done so far has been with HTML/JavaScript, which is the one thing that has most excited me over the last couple of years. But there’s very little of the community chaos that you get in web development. You are essentially developing for IE 10. So all the self-righteous, holier-than-thou web dev hipsters aren’t going to talk to you anyway. :) I’m not a standards guru, but from what I know, IE 10 is pretty good. And even if it’s not 100% standards compliant, since you are only developing for the one platform for desktop Win8 apps, it’s kind of a standard itself.  There’s none of the cross-browser / cross-platform stuff to worry about. Basically, you can just ignore all the noise and MAKE stuff. And that’s what I’m doing. And loving it.

On the job front, I’m still at Infrared5 and that’s all going pretty well. Although nothing jumps out as being hugely exciting there for me in the last year, there were no huge problems either. I did one project in ActionScript / Flex / Desktop AIR, which was pretty unique in that it embeds a Red5 server in the app itself to do local recording of video. I have Paul Gregoire to thank for the Red5 help and in hacking together a stripped down version of the Red5 server that could be run on the low end hardware we were targeting. It was quite a technical challenge and worked out pretty well. Most of the rest of the year I’ve been doing iOS stuff for a client of the company that keeps hiring me back. Earlier in the year I helped build out a custom iOS library for the client, and in the latter half, I’ve been helping to build an app based on that library – truly eating my own dog food! It’s an interesting situation to be working with the black box of a closed library that you helped build but no longer have access to the source of. A bit frustrating at times, but quite an eye opener as well.

So what’s in store for 2013? More of the same. Specifically, my plan for the moment is to participate in this: http://onegameamonth.com/ The One Game A Month… er… project? It’s not a game jam, it’s not a contest, it’s just a couple thousand people who say they are going to try to make a game each month for 2013. Fantastic idea. I’ve spent way too long on the game I’m currently working on. That’s a common problem with any personal programming project. There’s no deadline, so you fiddle with it forever, trying to make it perfect, eventually get bored with it and start something else. This boxes out your time. One month. Get it done. Ship it. The game I’m working on now will wind up being my January game, and I have a great concept for February. I’m excited about this.

I also really do plan to do more blogging. I’m going to try to put something up 2-3 times a week. Probably a lot of it will be about the game I’m working on at that particular time. Any tricks or tips, problems or insight.

Also, as many of you know from my tweets, G+ posts, other comments, and occasional mentions on this blog, I’ve been heavily into running in the last few years. This past year I ran my first two marathons and am now in training for my first ultramarathon, a 50K (31 mile) trail race in April. I don’t like to put too much of that info on this blog, but if you are interested to hear more about that, here’s another year in review post from that viewpoint, on my personal blog.

Send to Kindle

2 responses so far

Falling Balls Update

Dec 05 2012

Send to Kindle

At the end of October this year, Falling Balls was released into the Windows 8 Store. After just over a month, I thought it would be interesting to discuss how it is doing, and to answer the question, “should I build games or apps for Windows 8?”

Hard statistics.

Here you can see the download stats. It’s averaging roughly 900 downloads a day, with a best day of just over 1500, and generally trending up. The weekends usually see more downloads than the weekdays. You can also see the demographics of who is downloading the app.

As of this writing, the game has been downloaded about 25,000 times.

The dev center also gives you some pretty cool status such as average app usage per day. Amazingly, in mid-November, people were playing Falling Balls for an average of 17 minutes per day! Average! That’s insane. It’s now around 6-7 minutes per day, which to be honest, still amazes me.

Money.

So what about profit? I decided to follow the successful pattern of releasing the app for free and using advertising. I used Bing ads which integrate well in Windows 8 apps, but you can easily implement any other HTML-based ads in a Windows 8 HTML/JS application.

Here you can see daily ad revenue. There was a bug in my own code in the first release that was preventing the ads from showing up. Obviously, that got fixed on the 8th and has been generally uptrending since then, again with peaks on the weekends. Averages are in the range of around $5 on weekdays and $7-8 on weekend days. (The dropoff for the last day is just because the reports lag a day behind, so there is no data for today’s revenue yet.) In the three or four weeks that the ads have actually been appearing, I’ve made around $120-130. But I suspect that will increase a bit, especially since I’m planning a few upgrades to the game.

Summary.

So far, I can’t say that the game has been the runaway, oh-my-god-what-happened success that it was on iOS, but I’m sure there are a number of factors that play into that, such as the fact that iOS devices were broadly available for a year or so before the app store was open to developers. There was a huge base of people wanting new apps and games from day one. There is also a big difference between the mobile app store market and a mostly desktop / somewhat tablet based app store.

I’m hopeful that the trends will continue upwards as Windows 8 gains traction and more people get Win8 devices over the holidays and in general. But even so I’m not complaining. Already, I’m looking at a couple hundred dollars in passive income. Nothing to quit the day job over, but certainly welcome.

If the situation changes markedly in the future, I will be sure to report on it.

Send to Kindle

One response so far

Falling Balls for Windows 8 release 2 is out

Nov 08 2012

Send to Kindle

I pushed Falling Balls out the door with bare minimum functionality. In the week or so it’s been out though, it’s gotten a couple of thousand downloads and a solid 4 star rating. Early this week I decided to enhance it a bit with two new difficulty levels – “hard” and “ninja”.

In hard mode, the balls start coming out faster right away and you’ll see a lot more of them. If you had a decent score in the original mode, you’ll be hard pressed to get anywhere near that in hard mode.

Ninja mode is a bit faster than easy (original) mode, but the balls come at you from both directions. You can still last a while on it, but it’s far more challenging, and in my opinion, a lot more interesting.

I also fixed a bug which was preventing ads from showing up in most cases. I’m saying this because for most people it will look like I just added the ads in this release, but in fact they were there all along, just not working very well. Like the iOS version, the ads will only show after you die and will go away while you are in active game play. Feel free to click on them if you see something vaguely interesting, and support … me. :)

Send to Kindle

No responses yet

Falling Balls for Windows 8 now available

Nov 01 2012

Send to Kindle

Just got the email last night, Falling Balls is now available in the Windows 8 Store!

I’m really interested to see how this does. I’ve implemented Bing ads in the game, exactly the same way they are implemented in the iOS version, i.e. when you die, there is a banner ad in the top center of the screen. It goes away when you start playing, so it’s not there to distract you from game play. You don’t want to see an ad – don’t die! However, I’m not seeing any ads in the live app. It took a while to see any at all while I was testing, though it worked fine using a test ad account. From looking at various forum posts, I think they just don’t have that much inventory, so there is very low fulfillment rate. I may need to switch to another ad provider if Bing doesn’t pull through soon.

I also have some additional features I want to add to the game. Considering making them in-app purchases, but if I can get ads working a bit better, I’d be happy to keep them free.

Send to Kindle

4 responses so far

Windows 8 App Store Submission Process

Oct 26 2012

Send to Kindle

As of this writing, I’ve submitted two apps to the Windows 8 Store. The first one is Particle Art. This one took four tries to get approved. The second is a port of Falling Balls, which I just submitted for the third time and I’m pretty sure it will pass this time.

There are a few things I’ve learned in the process that I’m sure will make things go much smoother for my future submissions. And hopefully they will help anyone else going through the process.

First off…

Privacy Policy!!!!

In the current app submission flow, I feel this is not given nearly the emphasis that it should be. The wording makes it sound very conditional and almost optional. My apps do not use, store, or transmit any information from any user whatsoever, so I didn’t think I’d need this. But the truth is that it is almost certain that any app you create will need a privacy policy. This is a very good article on the subject:

http://gyorgybalassy.wordpress.com/2012/10/22/your-app-needs-a-privacy-policy-in-the-windows-store/

When I first got rejected for Particle Art, it was for lack of a privacy policy. in the online app submission process, there is a field where you enter a link to your privacy policy. I created a policy, put it on line, entered the link, and resubmitted. A few days later, rejected again. So you actually need to be able to display your privacy policy IN the app as well. There is a mechanism for this, which I discovered after a bit of digging around. Rather than go into it, I’ll link to Jesse Freeman’s article where he describes the steps:

http://jessefreeman.com/articles/windows-store-privacy-statement/

Submitted again. Rejected again. This time because the app was freezing. On the rejection report was a zipped file containing a screenshot and steps to reproduce the hang. It turns out that somehow one of the project files had somehow gotten removed from the project. It was still on the hard drive, but not referenced in the project, thus was causing a crash when it was referenced. This was another file in the settings panel and I think I had done a save-as to create the privacy policy settings, which resulted in only the new saved file being in the project, not both the original and new. Anyway, that was a simple fix – just add the file back to the project. Resubmit again, and now the app is in the store.

Lessons learned:

1. Privacy policy!!!
2. Completely test every aspect of your app just before you submit it.

Next was Falling Balls. I was still not a true believer in the privacy policy and was absolutely convinced that it did not need one. Rejected. Privacy policy added in app and online. Resubmitted again. Rejected again. Reason: crash. What??? I’ve played the thing repeatedly and done just about everything you can do with it and it never once crashed. Despair set in. Combed through code. Profiled app and found some huge inefficiencies there, which I cleaned up. But there was nothing definitive. Perhaps if the app was running on a low powered ARM device… ? Who knows??? I sadly considered resubmitting and crossing my fingers hoping that solved it. Decided to take another look at the rejection. OH… there’s a details report attached as a zip file. Missed that. What do you know… a screenshot with steps on how to reproduce the issue. Duh.

Turns out that I’d left a reference to my FPS counter in one particular spot in the app. I’d removed the FPS counter just before submission though. But if you did this one function, it would try to access it and crash. Solved and fixed within 2 minutes of seeing the detail report.

Lessons learned:

1. PRIVACY POLICY!!!!!!!
2. COMPLETELY TEST EVERY ASPECT OF YOUR APP JUST BEFORE YOU SUBMIT IT!!!

Summary

See “Lessons Learned”.

Send to Kindle

10 responses so far

Custom Windows 8 HTML Controls

Oct 12 2012

Send to Kindle

Building native Windows 8 apps in HTML and JavaScript is – dare I say it? – fun. I’ve been enjoying learning and building things with JavaScript over the last couple of years, but the cross-platform/cross-browser/cross-version issues can become a pain. And the 10 million competing libraries and micro-frameworks can be overwhelming. Everyone has their favorite and is happy to shove it down your throat with the slightest provocation.

But developing apps for Windows 8 has a kind of purity. There’s a single system and a single “browser”. The framework/library code is built in. Yeah, I’m sure you could probably pull jQuery or Backbone or whatever else in to help create your app, but there’s far less need.

There’s also the fact that you have various OS hooks, of which I’ve only scratched the surface so far.

Anyway, if you’ve been doing web dev in JS, you just might find doing Windows 8 apps a breath of fresh air. You’re using all the same tools – HTML, JS, CSS. You can use just about every standard HTML ui element, and with the default CSS files, they are rendered like standard Windows 8 controls.

But one of the more powerful features is custom controls. These are created by creating a div and giving it a data-win-control attribute of the name of a JavaScript “class”. When your app launches, you call args.setPromise(WinJS.UI.processAll()). This looks through the HTML for any divs with the data-win-control attribute and instantiates the class referenced there. This class builds up the custom element’s view and logic inside that div. There are a bunch of built-in custom controls in the WinJS.UI package, such as the AppBar, DatePicker, Lists, Rating control, Flyouts, Menus, Tooltips, etc. In addition, you can set a data-win-options attribute with a stringified object containing option name/values. These help to customize the new control.

So if you wanted to create a Date Picker, you just put this in your HTML:

<div id="date" data-win-control="WinJS.UI.DatePicker">

And if you wanted to set the current date in the picker, you can pass that as an option:

<div data-win-control="WinJS.UI.DatePicker" data-win-options="{current:'10/12/2012'}">

But even more powerful is the ability to create your own custom controls. Let’s do it. Create a new blank Windows 8 JavaScript project in VS2012. Create a new JavaScript file in the js folder. Name it DummyControl.js and fill it with this code:

WinJS.Namespace.define("bit101", {
    DummyControl: WinJS.Class.define(
        function (element, options) {
            // constructor
            console.log(element);
            console.log(options);
        }, {
            // instance members
        }, {
            // static members
        })
    }
);

Here we are defining a namespace called bit101. It will consist of an object with a single property called DummyControl. And bit101.DummyControl will be a pseudoclass defined with WinJS.Class.define. I know, I know. But that’s how it’s done and it’s pretty straightforward. The define method takes 3 arguments. The first is a function which becomes the class’s constructor. The next is an object containing instance members and then an object containing any static members. You can see that the constructor function gets passed the element that the control is instantiated in, and the options that are passed in in the data-win-options attribute.

You can now add the script reference and an instance of this control to your default.html file and run the app.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>CustomControls</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

    <!-- CustomControls references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
    <script src="/js/DummyControl.js"></script>
</head>
<body>
    <div id="dummy" data-win-control="bit101.DummyControl" data-win-options="{}"></div>
</body>
</html>

I passed in an empty object to options just so we could see something traced out. You should see this in your output:

[object HTMLDivElement][object Object]

Now we can start building out the control to actually do something. Instead of just logging them, we’ll save the parameters and call an init function. The init function will create a new h1 tag and append it to the control’s element:

WinJS.Namespace.define("bit101", {
    DummyControl: WinJS.Class.define(
        function (element, options) {
            // constructor
            this.element = element;
            this.options = options;
            this.init();
        }, {
            // instance members
            init: function () {
                this.h1 = document.createElement("h1");
                this.h1.innerText = this.options.message || "Hello world";
                this.element.appendChild(this.h1);
            }
        }, {
            // static members
        })
    }
);

The h1 tag’s inner text is set to the message property of the options, if it exists, otherwise it defaults to “Hello World”. Running this now should result in a large “Hello world” being displayed in the app.

We can then set the message to whatever we want via the options:

<div id="dummy" data-win-control="bit101.DummyControl" data-win-options="{message:'Windows 8 Rocks'}"></div>

Additionally, you can create methods that can be called on the control itself from external scripts. Let’s make a new function that allows us to change the message:

WinJS.Namespace.define("bit101", {
    DummyControl: WinJS.Class.define(
        function (element, options) {
            // constructor
            this.element = element;
            this.options = options;
            this.init();
        }, {
            // instance members
            init: function () {
                this.h1 = document.createElement("h1");
                this.h1.innerText = this.options.message || "Hello world";
                this.element.appendChild(this.h1);
            },

            setMessage: function (message) {
                this.h1.innerText = message;
            }
        }, {
            // static members
        })
    }
);

But how do we access that? Well first, notice that I gave the div containing the control an id of “dummy”, so it’s easy enough to find the div by saying document.getElementById(“dummy”). But that just gives us the div that contains the control, not the control itself. For that we access the winControl property of that div, like so:

var dummyControl = document.getElementById("dummy").winControl;

But, a very important thing to remember here: Earlier in the article I mentioned that calling WinJS.UI.processAll finds all the data-win-control divs and instantiates their controls. So you need to A. call this function, and B. wait for it to complete. The function uses the promises pattern, so all we have to do is something like this:

            args.setPromise(WinJS.UI.processAll().then(function () {
                var dummyControl = document.getElementById("dummy").winControl;
                dummyControl.setMessage("It works!");
            }));

Of course, this is a rather simple example created for demonstration purposes. In a real control, you can add all the elements, event handlers, styles, and behavior you want in there and create some pretty complex components. As an example, I’ve built a pretty full featured control called FPSDisplay. This displays the current frame rate of a running app based on requestAnimationFrame and a running bar graph of how the frame rate has changed over the recent past. All you have to do is include the fpsDisplay.js file in your HTML and create an instance like so:

<div id="fps" data-win-control="bit101.FPSDisplay" ></div>

Options include color, bgColor and position, which can be “tl”, “tr”, “bl”, “br” (top left, top right, etc.). Methods include start and stop which do the obvious.

Here’s the code in full for you to peruse though. I’m not going to comment on it though. Save it out and add it to your project and see how it goes.

WinJS.Namespace.define("bit101", {
    FPSDisplay: WinJS.Class.define(function (element, options) {
        if (!element) {
            throw "element must be provided";
        }
        this.options = options || { position: "tl" };
        this.element = element;
        this.init();
    }, {
        init: function () {
            this.child = document.createElement("div");
            this.child.style.position = "absolute";
            this.setPosition(this.options.position);
            this.element.appendChild(this.child);

            var canvas = document.createElement("canvas");
            canvas.width = 100;
            canvas.height = 50;
            
            this.context = canvas.getContext("2d");
            this.context.fillStyle = "white";
            this.context.fillRect(0, 0, 100, 50);
            this.context.font = "10px Arial";

            this.child.appendChild(canvas);

            this.text = document.createElement("div");
            this.text.style.font = "10px Arial";
            this.text.style.color = this.options.color || "black";
            this.text.style.backgroundColor = this.options.bgColor || "white";
            this.text.style.position = "absolute";
            this.text.style.top = "1px";
            this.text.style.left = "2px";
            this.child.appendChild(this.text);

            this.onVisibilityChanged = this.onVisibilityChanged.bind(this);
            document.addEventListener("visibilitychange", this.onVisibilityChanged, false);
            this.history = [];
            this.update = this.update.bind(this);
            this.start();
        },

        onVisibilityChanged: function() {
            if (document.visibilityState === "hidden") {
                this.lastTime = 0;
                this.frames = 0;
                this.elapsed = 0;
            }
        },

        start: function () {
            this.frames = 0;
            this.isRunning = true;
            this.elapsed = 0;
            this.lastTime = 0;
            this.animRequest = window.requestAnimationFrame(this.update);
        },

        stop: function () {
            this.isRunning = false;
            cancelAnimationFrame(this.animRequest);
        },

        update: function (time) {
            if (!this.lastTime) {
                this.lastTime = time;
                this.animRequest = window.requestAnimationFrame(this.update);
                return;
            }

            this.elapsed += time - this.lastTime;
            this.frames += 1;
            this.lastTime = time;
            this.animRequest = window.requestAnimationFrame(this.update);
            if (this.elapsed > 1000) {
                this.frames = Math.round(this.frames * 1000 / this.elapsed);
                this.elapsed = 0;
                this.draw();
            }
        },

        draw: function () {
            var min = 1000;
            var max = 0;
            for (var i = Math.max(this.history.length - 10, 0); i < this.history.length; i += 1) {
                min = Math.min(min, this.history[i] - 2);
                max = Math.max(max, this.history[i] + 2);
            }
            var range = max - min;
            this.history.push(this.frames);
            if (this.history.length > 50) {
                this.history.shift();
            }
            this.context.fillStyle = this.options.bgColor || "white";
            this.context.fillRect(0, 0, 100, 50);
            this.context.fillStyle = this.options.color || "black";
            for (var i = 0; i < this.history.length; i += 1) {
                var value = this.history[i];
                var h = (value - min) / range * 50;
                this.context.fillRect(i * 2, 50 - h, 1, h);
            }
            this.text.innerHTML = this.frames + " fps";
            this.frames = 0;
        },

        setPosition: function (pos) {
            // default tl
            this.child.style.left = "0px";
            this.child.style.top = "0px";

            if(pos.indexOf("r") != -1) {
                this.child.style.left = (window.innerWidth - 100) + "px";
            }
            if(pos.indexOf("b") != -1) {
                this.child.style.top = (window.innerHeight - 50) + "px";
            }
        }

    }
)
});
Send to Kindle

3 responses so far

My Windows 8 HTML/JS App/Game Dev Setup

Oct 11 2012

Send to Kindle

As of this writing, I have three Windows 8 apps/games in the pipeline. Particle Art has been submitted. Falling Balls is 99% done and will be submitted by the weekend, and another game I’ve started is a bit past the prototype stage and starting real development. I wanted to share some of the basic setup principles I’ve been using and some of the things I’ve learned.

First of all, in Visual Studio 2012 (Pro or Express) I create a JavaScript Windows Store blank app. This gives you all of the needed frameworks and references along with a default.html, default.js and default.css file. Running this will give you a blank app with some text that says “Content goes here”.

Looking in default.html we see this:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Game101</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

    <!-- Game101 references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
</head>
<body>
    <p>Content goes here</p>
</body>
</html>

Pretty basic. I change that to add a canvas:

<body>
    <canvas id="canvas"></canvas>
</body>

Now, go into default.js and you’ll see something like this:

// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
    "use strict";

    WinJS.Binding.optimizeBindingReferences = true;

    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                // TODO: This application has been newly launched. Initialize
                // your application here.
            } else {
                // TODO: This application has been reactivated from suspension.
                // Restore application state here.
            }
            args.setPromise(WinJS.UI.processAll());
        }
    };

    app.oncheckpoint = function (args) {
        // TODO: This application is about to be suspended. Save any state
        // that needs to persist across suspensions here. You might use the
        // WinJS.Application.sessionState object, which is automatically
        // saved and restored across suspension. If you need to complete an
        // asynchronous operation before your application is suspended, call
        // args.setPromise().
    };

    app.start();
})();

App Lifecycle

Now somewhere in here we need to kick off our game or app. The basic lifecycle of a Windows 8 JavaScript app is:

1. The WinJS.Application is instantiated and start is called on it.

2. The onactivated callback on the application is called. This checks to see what kind of execution state the app is in. It can be A. a new activation which means it is being launched for the first time or it is being launched after the user explicitly shut it down the last time or B. a reactivation which probably means that the app was in the background and the system decided it needed to close it down to save memory or whatever. Here, you can choose to restore it’s state to what it was when it was suspended (assuming you have saved that state) so it looks like it was just sitting there waiting for you the whole time. Whether or not you choose to do that, you are now at the place where you can start your own app logic.

3. But there’s one more line there:

args.setPromise(WinJS.UI.processAll());

This processes all the custom controls on the page. In addition to standard HTML elements, Windows provides some additional custom ui elements. These are defined on the page like so:

<div data-win-control="SomeCustomControlClass" data-win-options="{option:'someoption'}"></div>

The processAll function finds those items and fills them with visible elements and logic. If you are not using any custom controls you can ignore this line or even remove it and start your game or app logic right there. But if you do have custom controls, it’s good to hold off until they are all completely instantiated. You might think that you could just put your app logic after that line, but notice that it’s a promise method, meaning that it may not complete immediately. The solution is to use the then handler of the promise, passing in a function like so:

args.setPromise(WinJS.UI.processAll().then( function () {
    // start your app here!!!
}));

In general, that’s what I do, just to close the door on any issues that could arise from controls not being ready.

Main Game / App Object

Actually, I don’t put any significant code at all in default.js other than that then handler and usually a single line to instantiate my main game or app object. As you may know from reading this blog, I’m not a big fan of pseudo-JavaScript classes, so I create an object with methods as a sort of template and instantiate a customized copy of it using Object.create. Here’s the pattern that I’ve grown very fond of:

WinJS.Namespace.define("bit101.game", {

    create: function () {
        var obj = Object.create(this);
        obj.init()
        return obj;
    },

    init: function () {

    }

});

At first I was doing it a bit more by hand like so:

var bit101 = bit101 || {};
bit101.game = {

    create: function () {
        var obj = Object.create(this);
        obj.init()
        return obj;
    },

    init: function () {

    }

});

But I discovered the WinJS.Namespace.define function which does the same thing a bit more concisely. Either way, this gives us a bit101.game object which has a create function on it. The create method clones the object with Object.create, calls init on the new clone and returns the result. I can now kick off my game or app like so:

args.setPromise(WinJS.UI.processAll().then( function () {
    bit101.game.create();
}));

Of course, don’t forget to add a script tag in default.html to load your new script:

<script src="/js/game.js"></script>

The init function becomes the “constructor” of the object. I usually start out with something like this:

    init: function () {
        var canvas = document.getElementById("canvas"),
            context = canvas.getContext("2d");

        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

    }

I then make a model, a view, and an input manager with the same exact object setup.

    init: function () {
        var canvas = document.getElementById("canvas"),
            context = canvas.getContext("2d");

        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        this.model = bit101.model.create(canvas.width, canvas.height);
        this.view = bit101.view.create(this.model, context);
        this.inputManager = bit101.inputManager.create();
    }

Here, the model needs to know the width and the height and the view needs a reference to the model and the context. Passing “constructor” arguments to the objects is easy, just supply them to create and pass them to init and generally save them there. Here’s the model:

WinJS.Namespace.define("bit101.model", {

    create: function (w, h) {
        var obj = Object.create(this);
        obj.init(w, h)
        return obj;
    },

    init: function (w, h) {
        this.width = w;
        this.height = h;
        this.circle = {
            x: this.width / 2,
            y: this.height / 2,
            radius: 20,
            velocity: 0
        };
    },
    
    update: function () {
        this.circle.x += this.circle.velocity;
    }

});

I’ve added another object, circle, in there, along with an update function that updates the circle.

Here’s what the view might look like:

WinJS.Namespace.define("bit101.view", {

    create: function (model, context) {
        var obj = Object.create(this);
        obj.init(model, context)
        return obj;
    },

    init: function (model, context) {
        this.model = model;
        this.context = context;
    },

    draw: function () {
        this.context.clearRect(0, 0, this.model.width, this.model.height);
        this.context.beginPath();
        this.context.strokeStyle = "red";
        this.context.arc(this.model.circle.x,
                         this.model.circle.y,
                         this.model.circle.radius,
                         0, Math.PI * 2, false);
        this.context.stroke();
    }

});

I save the model and context and in a draw method I clear the context and draw the circle based on the current data in the model.

Then there’s the input manager. This listens for key events and sets a couple of variables, left and right, depending on what keys were pressed or released:

WinJS.Namespace.define("bit101.inputManager", {

    create: function () {
        var obj = Object.create(this);
        obj.init()
        return obj;
    },

    init: function () {
        this.onKeyDown = this.onKeyDown.bind(this);
        this.onKeyUp = this.onKeyUp.bind(this);

        document.body.addEventListener("keydown", this.onKeyDown, false);
        document.body.addEventListener("keyup", this.onKeyUp, false);
    },

    onKeyDown: function (event) {
        switch (event.keyCode) {
            case 37: // left
                this.left = true;
                break;

            case 39: // right
                this.right = true;
                break;
        }
    },

    onKeyUp: function (event) {
        switch (event.keyCode) {
            case 37: // left
                this.left = false;
                break;

            case 39: // right
                this.right = false;
                break;
        }
    }

});

And finally, the completed game object:

WinJS.Namespace.define("bit101.game", {

    create: function () {
        var obj = Object.create(this);
        obj.init()
        return obj;
    },

    init: function () {
        var canvas = document.getElementById("canvas"),
            context = canvas.getContext("2d");

        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        this.model = bit101.model.create(canvas.width, canvas.height);
        this.view = bit101.view.create(this.model, context);
        this.inputManager = bit101.inputManager.create();

        this.update = this.update.bind(this);
        window.requestAnimationFrame(this.update);
    },

    update: function () {
        this.getInput();
        this.model.update();
        this.view.draw();
        window.requestAnimationFrame(this.update);
    },

    getInput: function () {
        if (this.inputManager.left) {
            this.model.circle.velocity = -3;
        }
        else if (this.inputManager.right) {
            this.model.circle.velocity = 3;
        }
        else {
            this.model.circle.velocity = 0;
        }
    }

});

After creating all the objects, init sets up a call to update through requestAnimationFrame. The update method calls getInput, then updates the model and tells the view to draw. The getInput function checks the state of the inputManager and sets the velocity of the circle in the model accordingly. If this is all set up right you should see a red circle at center screen. Pressing left and right keys will move it back and forth.

Summary

Of course, this is vastly oversimplified, but is exactly how I would start a game. The model would gain many more objects and other methods to manipulate them. Many of those model objects would be defined in their own file with create, init, and other methods. Similarly, there may be several other views – player view, enemy view, score view, etc. These can all draw to the same context, but would have different logic for exactly what to draw and where. And the input manager would of course be very customized based on what kind of controls are being used.

newobj Snippet

As I’m using the same basic setup for every new object I make, I created a Visual Studio snippet to make it a bit quicker. This is a text file that goes in the following location:

C:\Users\<username>\Documents\Visual Studio 2012\Code Snippets\JavaScript\My Code Snippets

I’ve named it “new_object.snippet”. Here’s what it looks like:

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets
    xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>New Object</Title>
      <Shortcut>newobj</Shortcut>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>namespace</ID>
          <ToolTip>Replace with a valid namespace.</ToolTip>
          <Default>namespace</Default>
        </Literal>
      </Declarations>
      <Code Language="JavaScript">
        <![CDATA[WinJS.Namespace.define("$namespace$", {

    create: function () {
        var obj = Object.create(this);
        obj.init()
        return obj;
    },

    init: function () {

    }

});]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

Once that’s in place, you just type newobj and hit tab and you get the full expanded code, with the namespace highlighted and ready for you to type your actual namespace. I’ll be making more of these, I’m sure.

Send to Kindle

2 responses so far

« Newer posts Older posts »