While we’re waiting for “Corona UI” to come out, I put together a script that uses web popups and a script from Cubiq.org to create a very native looking/feeling iOS control.
It sounds strange, I know, but check it out for yourself here.
Even if you’re not interested in a native-ish wheelpicker ui control for Corona, you can still take a look at the lua source and learn a few tricks about how to extract data from a web-popup and bring it back into your app—it’s tricky, but it can be done as you’ll soon find out.
I actually put it together a while back, but didn’t get around to releasing it until just now. I thought I should since it’s been a while since I’ve released anything (been tied up with tons of projects).
Enjoy the script :-) I look forward to your comments/emails/tweets.
While it’s too early to reveal the name, this post will serve as the first “dev diary” entry for our upcoming Beebe Games title.
As you can see in the (somewhat tiny) screenshot, the game bares a resemblance to other games that use the PlanetCute Graphics Set—such as Base 2’s Walkabout—but we are actually not using Danc’s popular graphics set for this game.
When we came across the PlanetCute graphics on Danc’s website, we thought the style would match our game perfectly, so instead, Biffy created our graphics from scratch, using the “cutesy block style” of PlanetCute as inspiration.
Inspired Game Mechanics
When I was first introduced to the world of computers as a child, one of my favorite games that came pre-installed on our (I think it was Packard Bell?) Windows PC was Chip’s Challenge, a tile-based puzzle game that put you in control of a character named Chip.
Your goal was to collect all the “chips” and make it to the exit. The challenge was that you had to collect keys, push things around, and get through various obstacles to complete each level.
I’m not a big puzzle-game fan, but this game was different for some reason. It was one of my favorite games, and is still way up there in my book, despite it’s—admittedly ugly—graphical style (hey, it’s Microsoft, what can you expect in terms of style? heheh).
Another one of my favorites—which I discovered way later on—was a 1999 shareware hit called Dweep, which you’ve probably never heard of. It was similar to Chip’s Challenge in that you had to get from point A to B by figuring out how to get around all the obstacles in between, but the challenge’s were different enough that it really was a completely different game—but it gave me the same “feeling” that the older classic did, so for me, it was another winner.
You’ve probably already guessed that the two games above served as my source of inspiration for our next Beebe Games title. However, before beginning any development, I searched the App Store long and hard to see if there were any other games like the two I described above. Unsurprisingly, there’s quite a few.
I downloaded a bunch of them and while there are definitely some promising titles (many great games), none of them really gave me the same “feeling” as Chip’s Challenge or Dweep, which both had this strange ability to keep me engrossed in the game, even when I was ready to pull my hair out.
So while our upcoming game won’t be a clone of either of the games I mentioned (and is completely original in terms of the obstacles, maps, objects, storyline, etc.), I want to give credit to the two games that heavily inspired me because it’s likely that I might not even be a game developer if it weren’t for the enjoyment I got from those two games!
Sadly, both games are no longer on sale and are slowly but surely being forgotten.
So far, I have created a screen management script, simple 2D tile engine (using spritesheets), most of the game’s objects, and an internal map editor which uses the Corona simulator—all from scratch—so development is definitely progressing at a great pace.
My greatest challenge is going to be the level-design process. While my internal map editor helps with level-creation, design is a completely different story.
I have to figure out a way to introduce each item into the game at just the right pace so that the game can maintain a low learning curve, while keeping the game progression at a good enough pace so that it doesn’t get boring.
The next challenge is map difficulty. I have to make each level feel like the first, so that the player doesn’t get overwhelmed, but continue to ramp up the difficulty so that the player is constantly being challenged. With games like this, it’s very easy to make levels either way too easy, or way too difficult. Striking that perfect balance is absolutely essential if I want to capture the “feel” of old classics such as Chip’s Challenge and Dweep.
The last development challenge will be weeding out any flaws on each level. It’s easy to get so focused on creating the perfect map, that an obvious shortcut ends up right in front of my face, completely unnoticed.
I plan on overcoming ALL of these challenges by taking my time, taking a step back every now and then, re-visiting already-created levels, and doing some extensive beta-testing before final public release.
Excited? I think so…
Overall, to say that I’m very excited about releasing this game—even more-so than any of our other past launches—is a gross understatement. So far, the game’s turning out to be really great, and I think if you like a good challenge, you’re really going to enjoy playing ________.
And that’s it for the first dev diary entry for this game. Perhaps next time, I’ll be able to reveal the name and storyline (which will loosely tie into the “world” of another one of our games), so stay tuned.
Oh, and one last thing before I end this entry… we plan on releasing this game for free :-)
Until Corona SDK includes support for native desktop apps, something you might consider is creating “simulator apps” to serve as internal software tools for your Corona projects.
For example, for our next game, I created a simple tile-engine and each of the levels will be read from an external map file in a format that I created specifically for this upcoming game.
It would be very tedious, frustrating, and counterproductive for me to construct these map files in a text editor without actually being able to see the different tiles and objects being placed on the map, shown as they would be in the actual game.
The solution? I spent about an hour creating a map editor that would run in Corona’s simulator (iPad), which would allow me to visually design the levels of my game. I also implemented a “Save” button that would output the map files into the project’s “Sandbox” folder (within the Corona simulator, go to File > Show Project Sandbox) using the same format I created for my game.
I also included the ability to load a map file that’s already in the Sandbox folder if needed. When I’m finished creating/editing the map, I simply drag the map files into my game’s project folder, rename the files, and I then have a playable map! Now, the process of creating maps is fun, and not nearly as frustrating as it would be to manually hard-code the maps into a plain text file!
And this isn’t just something I plan on doing. I have done it, and it works great. I just can’t wait for Corona to officially support desktop publishing, so I can include “Save As…” dialog boxes and other things that just aren’t possible while being trapped in the project’’s sandbox.
What kind of internal simulator-only software could you write to help yourself out with YOUR projects?
Whether you’re developing games for iOS, Android, or some other platform, it’s going to be pretty easy for your app to get lost in the vast sea that grows at an alarming rate each and every day.
If you don’t want your app to drown, however, you’re going to have to take an active role in getting the word out. Nobody believes in your game better than you do—so the difference between nobody knowing about your game, and everybody knowing about it depends on the amount of effort you put into it not only during development (which is equally as important, obviously), but the effort you put into it afterwards as well.
A common scenario is that a developer pours their heart and soul (maybe?) into creating their masterpiece, and then once it’s finished, it’s “wait and see” time… almost like a break to take a step back and see how it performs out in the wild.
Unfortunately, hoping that the initial day of visibility is enough to make your game go viral is about as dependable as planning to win the lottery. Developing your game—I hate to say it—is only the beginning (which is why a high quality rapid development SDK such as Corona is essential, in my opinion).
After releasing five games to the iOS app store, I’ve made my share of mistakes, but I’ve learned from each and every one of them. I documented what works, what doesn’t, what needs improvement, what needs to be done, and what needs to be tried with every single one of my launches from here on out.
What I’m going to share with you is my personal plan-of-attack for our next release (and I’ll be sure to let you know how it goes once the game does get released). The following is exactly what I’m going to do pre-launch, and post-launch to help increase my chances of having the next successful game.
Beta Testing via TestFlight
I’ve personally suffered from a buggy release before, where I had to scramble to fix bugs and other usability issues as soon as the game is launched, and trust me, that’s the last thing you want to be doing on the “big” day.
For my next release, I plan on gathering a small handful of people and using TestFlight (a great, great service) to administer beta testing before I’m ready to submit the game for approval. I’ll have beta testers watch for bugs, and I’ll also monitor any usability suggestions to see if they will actually benefit the game (and not just change things for the sake of someone else’s personal vision for the game) and then adjust accordingly.
Then, once the first beta testing “phase” is over, I’ll gather another small handful of people to see if they catch anything that the first group didn’t. I’m pretty impatient, especially when it comes to releasing a completed game (especially since you have to wait out a grueling approval period), but I’ve learned that testing is of utmost importance.
You don’t want your beta testers to be the first ones who leave your 1 or 2-star ratings in iTunes. Unfortunately, I learned that one the hard way :-(
Social Networking Services
Prior to doing any kind of promotion, I’ll be setting up a Twitter account and a Facebook page dedicated solely to this next release. This will give me a way to track user interest before the game is even launched (followers), and also provide a more focused platform for delivering news, announcements, requests, etc.
Pre-Launch (Coming Soon) Trailer
Either mid-way through development, or once the game has been submitted to the App Store for approval, I plan on creating a short “Coming Soon” trailer and uploading it via YouTube. This trailer will be used as the basis of most of my promotional efforts and will help build some initial “buzz” before the game is actually released.
I’m not very experienced in creating trailers, but it doesn’t have to be hollywood quality. It just needs to be short, entertaining, and show off the best of what your game has to offer. The trailer I plan on creating is going to be simple, but I think it’ll be effective in getting the viewer to want to play the game and share the trailer with others.
Here’s a short summary of how I plan on having the video play out:
Trailer starts with the Beebe Games logo.
Small animation on the logo, directly relating to the game (I won’t spoil it just yet).
Black screen, game logo pops up (very bold).
The next screen is just a few words describing a main feature (“XX Levels”), and then the next screen following that will do the same (all this happening just seconds apart).
The next screen will be a couple seconds of gameplay footage (not enough to let them know what’s going on, but just enough to peak their interest). The screen will flip one-two times showing more gameplay footage.
More features, more gameplay footage. That whole process will repeat a couple of times until…
Black screen shows: “Coming April 2011” (or projected month of approval), the Twitter/Facebook links, and of course a link to the Beebe Games website. A short animation (continuing from the initial intro-animation) also plays and the trailer ends there.
Once the game is released, I’ll modify the trailer (possibly include more content) but change the “Coming Soon” to “Now Available” so I can still use it for promotional purposes post-launch.
All of the above can be done relatively easily if you have a few Flash skills (or are well versed in manipulating Corona transitions), have some kind of screen recording software, and can use iMovie to cut and splice things up (and publish, of course).
Word of Mouth
While I’m waiting for the game to be approved (and also once it is finally approved), I’m going to be blogging about the game, posting to the Facebook/Twitter pages, starting new threads at the appropriate forums (not spamming, notice how I said appropriate), participating in existing threads (while a link to the trailer sits in my signature), and sharing the trailer in as many places as I can.
This is your chance to go crazy, and be evangelical about your upcoming game… just don’t participate in SPAM.
Press Release on Launch Day
Before launch day, I’ll have written up a press release that I plan on distributing on the day of launch. You can either hire someone to do this for a fee, or if you’re a decent writer you can do it yourself (there are plenty of guides online that can help you with the format and content).
Distribution will be handled through a service called prMac.com, which I haven’t personally used, but I’ve heard good things about. It’s very affordable too so I hardly consider it a risk. If you know of a better one for iOS games, please let me know.
Try Your Best to Get Reviews
This is hit or miss, because there is a vast amount of games being submitted and nearly every one of them is being sent out to reviewers. I’m going to try my best to get as many reviews of the game as possible once it’s released, and then just hope for the best from there (that’s really all you can do).
I’m not going to be too bummed out if my game doesn’t get many, and you shouldn’t be either… give it a good shot, but then move on. There’s plenty of other things to do.
OpenFeint Free Game of the Day
Since our games often use OpenFeint, I always take the opportunity to submit my games to their “Free Game of the Day” service. If you’re approved, you’ll set your game free for a day and it’ll be promoted on FreeGameOfTheDay.com, which will drive TONS (and I’m not kidding), TONS of downloads to your app.
You’ll also experience a nice sales boost (either during, via In-App Purchases) or after the promotion once you game is set back to paid (you’ll share the profits with OpenFeint for that day and for a small period of time after, but hey, they helped you out so why not?).
Not all games are approved (they are pretty strict, actually), but it’s worth a shot. I have high hopes that our next release will be featured on that site in the coming months after launch.
There’s other similar services that you should try to get featured on as well. Another great one that I’ve used is freeAppCalendar.com.
Monitor Feedback and Update!
Whether it’s via Email, your Facebook/Twitter, or even iTunes customer reviews, you should be monitoring the feedback on your game and start constructing your first update ASAP, because it could be weeks before the update is available for your customers to download.
Like I said, I’m not perfect, and not any one of our five games have applied ALL of the above, because all of that is an accumulation of knowledge I’ve gained from my current experience as an app developer.
However, you can bet our next release will apply each and every one of the things I mentioned above, and as a bare minimum, yours should too. That is, if you want others to know about your game!
If you don’t feel excited enough about your game, or don’t think it’s “good enough” to warrant that kind of energy and effort, then perhaps it’s time to go back to the drawing board and make sure your app has all the elements of a successful game before even thinking of making it more visible.
Good luck, and here’s to your next release :-)
This post is part of iDevBlogADay, a group of blogs by indie iPhone developers featuring two posts per day. You can subscribe to iDevBlogADay through RSS or follow the #iDevBlogADay hash tag or @idevblogaday on Twitter.
After releasing five games in the iOS App Store, it’s hard for me to imagine just how I got along without using Corona’s built-in spritesheet support… that is, once I discovered TexturePacker by code’‘n’‘web.
When I worked on our original title, Doodle Dash (now Tilt Monster), I started coding the game with spritesheets, but I was running into some significant roadblocks (all of which are a result of Corona “Game Edition” being in alpha at that particular point in time):
Because the game didn’t have any levels and was on-going, after a random amount of time, the character’s sprite would stop animating and would get stuck on one of the frames. The only way to get the sprite animating again was to close out of the app and relaunch.
Actual creation of spritesheets was a tedious process, to say the least. On top of that, if any adjustments needed to be made to any of the frames, it added a whole new layer of complexity to the whole thing.
While there was external sprite-creation tools, Corona’s Sprite API (at the time) was very limited and didn’t support the formats and features that a lot of other tools incorporated into the spritesheets.
Implementation was a little confusing and still a little buggy at the time.
Once the iPhone 4 and iPod touch 4 came out, there was apparently no way to get spritesheets working with dynamic content scaling, and that was the deal-breaker for me (I hate the ‘blurry’ look of non-optimized games on 4th generation iOS devices).
Because of those issues, I decided to use a module called movieclip.lua for all of my animation needs because I felt, at the time, that it was really my only option because it could be modified to work with dynamic content scaling (for retina displays), and it wasn’t giving me the “freeze frame” issue I was experiencing with spritesheets.
Since then, all of the alpha-related issues above have been fixed and the Corona Sprite API has been vastly improved and expanded on (and is even compatible with retina displays now), but I was already used to using movieclips and everything seemed to be working fine so I just stuck with it.
Recently, I was doing work for a client and they had a particular animation sequence where each frame took up a significant chunk of texture memory. It was bogging down the app and in many instances causing it to crash.
Someone had suggested I try using spritesheets, so that way only one image needs to load and the animation can be handled accordingly.
I was on an extremely tight schedule so I didn’t have time to create a spritesheet manually and also brush-up on the Corona Sprite API, so I asked about any recommended software that’ll help me with the process… and that’s when TexturePacker was brought to my attention.
I downloaded the Essential Version (free) and within minutes was able to create a spritesheet, export to Corona, and begin using it in my project! At that point, TexturePacker won some major points for me and I had planned on revisiting it after I completed that project.
That little experience alone got me more interested in switching to spritesheets for my own projects, but what really proved to me that spritesheets really are more superior than movieclips was that the suggestion to use spritesheets actually worked. We got the animation going and the project was able to move forward from there.
The Benefits of Using Spritesheets
I always knew that in theory, spritesheets are better than movieclips, but it wasn’t until I had done more research that I realized how they completely blow movieclips away:
Loading one image vs. many helps improve texture memory usage, and also speeds up your app by having to draw only one image vs. many.
Being able to “alias” similar image frames to be used in multiple animation sets helps to significantly reduce not only the file size of the spritesheet, but the amount of texture memory that is used while the app is running (more on this later).
Control the exact amount of time between each frame of animation (this is actually a limitation of movieclip.lua).
Creation of display objects that are associated with a spritesheet is much quicker (since no new image loads are actually taking place).
Eliminate a major memory leak (currently) associated with movieclip.lua by avoiding movieclip.lua altogether.
Probably more benefits that I haven’t thought of at the time of this writing.
However, even though there are a lot of benefits to using spritesheets over movieclips, there was still a major drawback to using spritesheets (for me anyway), and I mentioned it before:
Actual creation of spritesheets was a tedious process, to say the least. On top of that, if any adjustments needed to be made to any of the frames, it added a whole new layer of complexity to the whole thing.
And that’s where TexturePacker comes in.
Creating an actual spritesheet is as simple as importing your images into the app and clicking ‘‘Export’ … and while that would have been enough for me to use it, TexturePacker does so much more than just that. You can visit the product page for a list of features, but some of my favorite ones include:
The ability to import your images and have your spritesheet created instantly.
Option to use MaxRects algorithm to decrease the overall texture size of the spritesheet (as much as possible anyway).
Auto-aliasing. I mentioned this earlier, but it’s actually very complicated and time-consuming to implement. That is, unless you’re using TexturePacker, in which case it’s as simple as checking a box and exporting to Corona.
Autosizing, and the options on the left make the creation of spritesheets, exporting to Corona, and importing into your Corona project mostly effortless.
TexturePacker actually supports several platforms, but I only use Corona so that’s the only one I tested out during this review process.
TexturePacker + Spritesheets vs. Movieclips
I decided to run a little experiment to see the advantages of spritesheets vs. movieclips first-hand. The experiment consists of a simple app that displays a simple glowing star animation (looping indefinitely) in the middle of the screen.
One project uses movieclips, the other uses spritesheets (created with and exported out using TexturePacker).
The animation consists of 61 frames, so that’s 61 total images for the movieclip project and just one image for the spritesheet project.
For the experiment, I used the following code to keep track of Lua memory and texture memory for each app:
Because I used TexturePacker with the auto-alias setting turned on (and MaxRects algorithm), the exported spritesheet only consisted of 31 frames (that is awesome, considering the original animation called for 61 frames) and the dimensions came out to be 256x512.
So there you have it. First-hand proof that spritesheets are superior to movieclip animations in just about every way.
To put the results into a little better perspective, here are some percentages (in regards to that specific project):
movieclip.lua uses about 17% more memory than the same animation using spritesheets.
movieclip.lua uses about 87% more texture memory than the same animation using spritesheets.
Of course, your results will vary depending on your project and specific animations, but I’m confident that in any case, whether or not the percentages are the same as my test project, spritesheets will always outperform movieclips significantly.
But remember, it’s not just spritesheets.
I personally wouldn’t have the patience to manually code in things like aliasing, the MaxRects algorithm, or even just creating spritesheet images if it weren’t for software such as TexturePacker, which makes the whole process almost effortless.
If you create games and use the Corona SDK or any of the other supported platforms, then TexturePacker is not only recommended, but is absolutely essential in my opinion.
I recommend downloading the “Essential Version” for free to try it out, but I highly recommend upgrading to the Pro version if you plan on using spritesheets in your final production.
When I first started using the Corona SDK and programming with Lua, one of the things that got to me was the structure of the Lua files, and the goal of keeping everything local.
I understood the benefits of using local variables and functions over globals, but putting everything into practice often felt like I was putting together a complex puzzle just trying to keep things local.
This was mainly because when you define a local variable or function, like so:
local myVariable = 100
You cannot access that variable in lines before it, as illustrated below:
And that’s exactly what caused the “puzzle” effect as I like to call it. Because inevitably, some function, somewhere else in the module would need to access that variable but not be able to simply because of the location it was defined in the code (even if during execution, the variable was set at the proper time).
Then, I learned about a wonderful thing called forward referencing.
Forward referencing is simply defining a variable before you intend to use it, but it provides a frame of reference for other code/functions that need to use the variable. And as long as the forward reference is local, then it will remain local throughout your code (unless you define it as local again in a separate codeblock).
Now, this may seem very obvious, but what’s not always obvious to everyone (even to me when I first started out), is that in Lua, functions are also variables… which means you can forward reference functions as well.
This first example is the “puzzle effect” (that can really get out of hand when you have hundreds or thousands of lines of code):
local callBack = function()
myFunction() --> ERROR: myFunction() does not exist
print( "Hello World" )
callBack() --> will produce error (see above)
And here is the same code above, but this time, with a forward reference:
local myFunction --> forward reference
local callBack = function()
myFunction() --> output: "Hello World"
myFunction = function() --> still local
print( "Hello World" )
And that’s where forward referencing really takes the cake. Notice how if you have a forward reference in your module, you simply define the function later on as you would a global, but magically, the function remains local (because of the forward reference).
So if you’re stuck in the “puzzle effect” or have just resorted to using globals to overcome this issue, then look no further, because forward referencing will save you (from going insane).
Biffy’’s Latest Graphics Inspiration. Danc from Lost Garden released a free set of prototyping graphics in 2007 that he dubbed “PlanetCute” that I’ve actually seen in quite a few iOS and flash games since then.
Well, Biffy and I came across those graphics quite a while ago, and they have since become her latest inspiration.
For our next game, Biffy will be creating (from scratch) graphics that closely resemble that same style (blocked tiles, circular characters, etc). You can get a quick preview of a few of the characters here. As you can see in the background, the dirt “blocks” closely resemble the one’s from Danc’s PlanetCute, but they were in fact re-created from scratch by Biffy.
I’ve got a few contract projects I need to get out of the way, but once a get a window of time, it’s full-speed ahead with our next release. This one’s going to be our best yet.
Once the game is in “beta” status, I’ll be organizing a group of about 10 or so people on TestFlight to test the game extensively (to catch any bugs or provide feedback) before the game goes live.
Please send me an email if you want to be a beta tester. I’d very much like it if those who are planning on becoming a beta tester already have their TestFlight account set up (it’s easy) before I’m ready to begin the testing process.
This game will also have it’s own unique twitter handle, but stay tuned for that.
Remove any associated event listeners from the object.
Call removeSelf() on the display object.
Set the display object’s variable to nil.
In the latest iteration of cleangroup.lua (1.1), as a “backup defense”, I added a check for any touch listeners to display objects before they are removed. You should always follow the best practices above, but the new update should help &just in case you forget to remove any touch listeners from an object before calling removeSelf().
The other day I was browsing the Corona forums to see if I could help anyone out who hadn’t already been helped, and I stumbled upon a thread where a particular member was confused as to why all of the children display objects in a group weren’t being removed when removeSelf() was being called on the parent group.
I replied and told them that all of the children display objects are NOT removed when a group is, and then pointed them to the cleanGroups() function that is currently used in Ricardo Rauber’s popular Director Class—I said that’s what I use in my projects.
To my surprise, another member (FrankS) replied and pointed out that the cleanGroups() function may not be entirely efficient in all scenarios (and could even lead to memory leaks… ouch!), and generously provided an alternative.
After that, another member (p120ph37) replied and provided their own solution, which is actually a patch for the built-in display.newGroups() function that will remove all child objects AND groups just by calling removeSelf().
The only catch to p120ph37’s solution is, in order for it to work you must place his display.newGroups replacement at the very top of your main.lua file, before any groups are created in your app (not really a “catch” though, just an important warning).
Since both are really great solutions, and since the first one (FrankS) actually calls removeSelf() on objects and groups, then why not combine both for maximum effect? So that’s exactly what I did.
To use it, place cleangroup.lua in your project’s folder and make sure you put the following code at the top of your main.lua file, before any other “require” statements, and especially before any calls to display.newGroup():
require( “cleangroup” )
Then, when you want to get rid of a group (and all of its children, child groups, etc.), just call:
cleanGroup( myGroup )
myGroup = nil
And that’s it. This is a perfect example of how simple collaboration and participating in constructive forum threads can help make everyone’s projects better in some way.
Happy memory-leak prevention and code optimization :-)
UPDATE: The script has been updated to version 1.1, which will check a display object for a touch listener and remove it from the object before calling removeSelf(). The download link above has been updated as well.
First Corona SDK Developer Kitchen on March 23rd. Everyone’s invited to the Ansca Offices to talk about your Corona SDK apps, issues, etc. in person. I highly encourage anyone who can to try to attend.
Biffy and I will be there, so if you feel so inclined, you can shoot any questions our way as well. See you there!
It’s thinner than probably anything else that’ll be released anytime soon.
It’s going to be blazing fast—and if anything else comes out this year that’s faster, is it even going to be noticeable from a consumer’s standpoint?
It has an eco-system and marketplace that’s better than anything else out there.
It comes in white and black… and even has some unique “Smart Covers” that’ll be available for it.
And here’s the kicker: it’s starts at just $499. My guess is that it’s going to be priced lower than most other iPad “competitors” out there.
From the average consumer’s standpoint (e.g. non-geek, which is most everyone), there’s really no reason to buy a different tablet over the iPad. And that was the case before the iPad 2 was announced.
I actually feel very sorry for potential competitors out there.
On the other hand, I personally think competitors have a chance with the 7-inch form factor because it’s awesome for gaming, checking email, and reading website feeds. I actually like the original Galaxy Tab a lot, but it’s way overpriced. Don’t get me wrong, it has way too many shortcomings (software-wise), but I think it has a lot of potential (or had, anyway).
So I think the Nook (priced just right) with it’s supposed upcoming update that’ll provide access to an “app store”, has a good chance of making it in the tablet market.
BUT, if Apple comes out with an iPod touch with a 6-7 inch screen (as was rumored), then I guess it’s back to the drawing board.
UPDATE: I’ll hold off anymore opinions about iPad dominance until the TouchPad and HP really start moving forward with webOS (out in the public anyway)… because it looks very promising.