Showing posts with label android. Show all posts
Showing posts with label android. Show all posts

Monday, October 6, 2014

Reflections on Android

I used to have an iPhone. I purchased the 3GS the day it was released and used it for 2 years. It was a great phone. I wrote a game for it and everything (although I never published it to the App Store). But when it came time to upgrade, I switched to an Android phone.


The iPhone/Android thing is like the Mac/PC debate from my childhood. Macs were extremely expensive (and still are, I guess) and less common. They couldn't run all the games I wanted. PCs were everywhere. They were cheap, and I could even build one myself. Since they were more common, they got more software written for them.

You'd think it would be like that today. There are tons of Android phones out there. Everybody can get one. They give you one for free with a cell phone contract. There's no waiting in line outside an Apple store for a week to get one. Android should be the first platform for which anyone develops software.

But it's not like that at all. Everyone develops for iOS first, and then maybe Android later. It's not as bad as it used to be, but it's not that great either.

What's wrong? Most people will tell you, and I am forced to agree, that it is harder to develop for Android. There are just too many devices with too many hardware-specific quirks. There are too many versions of the OS out there as well.

It's unfortunate that it has to be this way. Back in the Mac/PC days of yore, the fact that there are 1.34 bazillion hardware configurations for PCs didn't matter. Well, maybe it mattered a tiny bit, but for the most part we didn't worry about it. The OS took care of most of that for us. The PC ran DOS or Windows (depending on what year we're talking about) and that's all you had to worry about. New versions of the OS weren't released that often, so you had a longer cycle to catch your software up to the latest version. But if the operating system is supposed to abstract away all the difficult parts of working with a variety of different physical hardware, and Android app developers are having a less-than-ideal experience with that, does that mean that Android is a bad OS?

Maybe I'm being too hard on Android. When I think back, sure MS-DOS 6.22 would allow any game designed for MS-DOS 5+ run on my computer, but if I didn't have one of 2 supported sound cards I would hear no game music. I didn't blame that on DOS then, and I guess I shouldn't blame Android now.

Who do I blame, if not Android? Do I blame the hardware manufacturers for poor drivers? Do I blame the application developers? Do I blame it on the rain? Maybe my whole analogy is just flawed. Phones today are computers, more or less, but perhaps I am drawing unrealistic parallels between my Galaxy S3 and my 486SX Packard Bell.

I better stop typing now before this turns into a crazy rant or something. But I might buy another iPhone someday.

Amphibian.com comic for 6 October 2014

Wednesday, August 13, 2014

Just How Mobile?

I'm sure you're familiar with the Native App vs. HTML5 debate. There's a lot to be said in that one. As a developer, I would much rather make a single HTML5 web app instead of native apps for both iOS and Android.

However, I know that such a course of action would very likely be a bad idea. Don't get me wrong, I love HTML5. But I've seen very few cases where an HTML5 solution is on par with a native app solution. There are some exceptions, and it very much depends on what your particular app is doing.

But HTML5 is getting better. I fully except that someday mobile apps will do things in mobile browsers that are quite impressive. That day is not today.

One place in particular that shows the mobile web's shortcomings is in games. There are many examples of good HTML5 games that are playable on the desktop browsers, but I have trouble finding good ones that play well on mobile browsers. Even very simple games just get awkward on mobile devices.

So if you decide to go native, you'll have to make apps for both iOS and Android. But what if you decide that your particular app is simple enough that you can do it in HTML5? You might want to consider making two web apps, one for desktop and one for mobile. Oh, "that's silly" you say. Everyone knows that you just use responsive design and make one web app.

Or do you?

I read this article, in which the author makes the case that your mobile use cases might be so different from your desktop use cases that it makes more sense to make a second web application just for mobile users. I'm certainly a big fan of understanding your requirements (and use cases) well before developing your software.

Here's the article. Give it a read.

Is responsive design killing mobile?

Think about it.

Amphibian.com comic for August 13, 2014

Friday, March 22, 2013

Virtual D-Pad Killed by Geometry

I hate virtual D-pads in mobile games. The D-pad was great on my Nintendo Entertainment System, but trying to play Mega Man II on my iPhone with the standard touch-screen replacement for tactile control made me regret spending $2.99 on the game. With nothing to stop my thumb from sliding right off the control zone, Mega Man plunged needlessly to his death so many times. So many times. Oh, the humanity! Well, in this case, the android...ity? Androidity? Is that a word? Feel free to substitute another word in your head when you read this. A word that you would use to express anguish over the massacre of heroic humanoid robots.

So let's just say I hate virtual D-pads. In the Android version of my FFZ game, I was not about to use one. There are a few alternatives that people have come up with, but here I'm going to talk about my current favorite and how I implemented it. It just took a little geometry.

What I wanted was a system where I could swipe my finger anywhere on the screen, and then my frog would move in a similar way. I swipe down and to the right, the frog moves down and to the right by the same distance. I don't have to start my swipe on the frog, so I don't have to block anything on the screen that I don't want to. I basically just want to create a vector with my finger that is then applied to the frog.

Doing this seemed fairly simple. I would just need a class that could represent the line segment created by the finger swipe, and then create a parallel line segment for the frog to move along.

Formula for a Line


Remember back to high school geometry class. The standard equation for a line is
y = mx + b
where m is the slope and b is the y-intercept (where the line will cross the y-axis). Slope is really important in this case, since that's basically what I want to duplicate in a second line for the frog's movement. Remember, lines with the same slope are parallel.

How, then, does one calculate slope? If you have a line, take any two points on it. Let's represent these two points as (x1, y1) and (x2, y2). Subtract y2 from y1 and divide that by the value of x1 minus x2.
m = (y1 - y2) / (x1 - x2)
The two points I'll use are the positions of the start of the touch event and the end of the touch event. So here's what my FrogPath class looks like so far.

public class FrogPath {

  private float x1;
  private float x2;
  private float y1;
  private float y2;
  private float slope;
  private boolean vertical;
 
  public void setStart(float x, float y) {
    this.x1 = x;
    this.y1 = y;
  }
 
  public void setEnd(float x, float y) {
  
    this.x2 = x;
    this.y2 = y;
    this.calculateSlope();
  
  }
 
  private void calculateSlope() {
    if (x1 - x2 == 0) { // don't divide by 0! no!
      slope = 0;
      vertical = true;
    } else {
      slope = (y1 - y2) / (x1 - x2);
      vertical = false;
    }
  }

}

Note the special handling for lines that go straight up and down. If there was no change in the x values for the two points, you'll divide by zero if you're not careful to check for that. Instead, a vertical line is said to have no slope. The formula for a line with no slope looks a little different, it's just x = n. The y value can be anything, but x will always be the same and there's no y-intercept. It's a little different than a horizontal line, which has a slope of 0. You can use the standard formula for those types of lines, but the value for m is 0 which essentially eliminates x from the equation. You're left with just y = n where n is always equal to b, because the line will cross the y-axis at the same value as every other point on the line! Consider the horizontal line y = 2, for example. Anyway, the point is that we have to perform special handling for vertical lines but not horizontal ones.

Thanks to Garrett Bartley for the Virtual Graph Paper I used here! 

So in my Android app, when I get an ACTION_DOWN MotionEvent I create a new FrogPath object and set the start coordinates. I hold on to that object until I get an ACTION_UP event, at which time I set the end coordinates. The FrogPath object calculates the slope of the line. That was the easy part!

Can We Get There from Here?


Now I have a slope and I have the current coordinates of my frog. I calculate the distance I want the frog to move, based on his speed and how much time passes between animation frames. What now? To calculate his new position, I have to figure out new coordinates that are on a line with the calculated slope that passes through the current coordinates. These new coordinates have to be the calculated distance from the current coordinates. Sound easy? Let's look at the picture...


Here we can say that c represents the distance we want to move the frog along the line. We know where the frog is now. Your first thought might be to call on your old friend Pythagoras and do that whole a2 + b2 thing. Sorry, but Pythagoras can't help you here. There's just not enough information. We need to find both a and b, and we can't do that with just c. This is where it get's tricky. You need to look at the problem in a different way. What if instead of seeing a triangle, you see a circle?

We can figure out the next position of the frog using the formula for a circle and determining where a circle centered at the frog's current coordinates and with radius r will intersect with the line. You may not be as familiar with the formula for a circle as you were with the formula for a line, but here it is. If the coordinates for the center of the circle are represented as (c, d) and a point on the circle is represented as (x, y) and r is the radius, the standard form circle equation is
(x - c)2 + (y - d)2 = r2
It might look crazy, but if you think about it, we have enough information to solve the problem if we combine the equation of our line with the equation of our circle. We know c and d, because those are the current coordinates of the frog. We know r because that is the distance we want the frog to move. And we know y (in terms of x anyway) because the line formula is y = mx + b. We know m because that is the slope. We can find b because we have a point on the line (the frog's current coordinates) and the slope. That's everything. Just plug it all in and solve for x! If you factored it all out, you'd come up with an equation like this for x:
x = c ± r / √(1 + m2)
Now you might notice that plus/minus thing in there, and rightly so - if you look at the picture above it clearly shows that the circle intersects the line in two places. How do you know which x value you want? Simple. You go back to your original two points that you used to calculate the slope in the first place. If the x value for the end point is greater than the x value for the start point, do a plus in the equation above. If not, do a minus. This basically means that if the user moved their finger from left to right you want to pick the intersection point on the right to keep the frog moving in the right direction. Pun intended.

We're almost done now. We can solve for x. But we still need a y value for the frog's new coordinates. Back to the line formula! Take our newly acquired value for x and plug it into our line equation y = mx + b along with the known values for m and b. You'll easily get y and now you've got a coordinate pair!

Just one more minor note before we get to the code. Remember that whole vertical line thing? Yeah, we need to handle that. But, good news! If we have a vertical line we don't need to mess with any circles or triangles or dodecahedrons or anything. Just add or subtract the distance moved from the current y coordinate (again, depending on if the original swipe was up or down) and return that paired with the current x coordinate.

Here's the two new methods that should be added to the FrogPath class shown above:

private float yIntercept(float x, float y, float m) {
  return (y - (m * x));
}
 
public float[] getNextPoint(float c, float d, float dist) {
  
  if (vertical) {
 
    float yp = d;
    if (this.y2 < this.y1) {
      yp -= dist;
    } else {
      yp += dist;
    }
    return new float[] {c, yp};
   
  } else {

    float b = yIntercept(c, d, this.slope);

    float xp = 0f;
    if (this.x2 < this.x1) {
      xp = (float) (c - (dist / (Math.sqrt(1+Math.pow(this.slope, 2)))));
    } else {
      xp = (float) (c + (dist / (Math.sqrt(1+Math.pow(this.slope, 2)))));
    }
    float yp = (this.slope * xp) + b;
    return new float[] {xp, yp};

  }
  
}

Just note that I return the new coordinates as an array of floats where the x coordinate is at position 0 and the y coordinate is at position 1. You could easily substitute some kind of object that represents a point if you prefer.

The only thing left to do is to figure out when to stop moving. That task is relatively simple, you just have to keep track of the total distance moved and stop when it equals the distance moved in the original screen swipe.

So that's it. That's how I used geometry that I probably should have learned in high school to defeat the dreaded virtual D-pad in a mobile game. And speaking of defeating something, who do you think would win in a fight between Pythagoras and Archimedes? Leave your comments below. My money's on Archy. Yeah, that's right. I called him Archy. Archimedes had a nickname. That's what his friends called him.

Thursday, January 10, 2013

Getting Started with my OUYA

So now I have my OUYA Dev kit all unboxed and hooked up to the TV and everything. The screens and welcome video look nice, but to load anything on it I needed to get it hooked up to the computer and detected as a valid Android device.

I like to do my development in Eclipse on Windows. I know, I'm crazy. I like my Mac and all, but when I write software (except for iOS of course) I've always been in a Microsoft environment. Maybe it's because my first introduction to programming was BASIC in DOS. Maybe? But from BASIC to Turbo Pascal to C to Java, I've always used a DOS or Windows PC. I'm now on Windows 7 64-bit and of course the OUYA wasn't detected as a valid device when I plugged it in.

The Windows section of the setup information for OUYA devs is a little sparse right now (ok, it's empty) but the forums did provide me with a solution, which I will now share. Hopefully they'll provide some kind of driver with the OUYA when it is released to the general public in a few months, but if not this trick will probably still work.

First, find the Android device driver file provided by Google in your Android SDK. Mine was

C:\Users\User Name\AppData\Local\Android\android-sdk\extras\google\android_winusb.inf

and yours is probably somewhere similar. Open that file up in Nodepad and add these two lines in the [Google.NTx86] section:


%SingleAdbInterface% = USB_Install, USB\VID_0955&PID_7100&MI_01
%CompositeAdbInterface% = USB_Install, USB\VID_0955&PID_7100&REV_0232&MI_01


Then you go to your Device Manager and find the unknown device. It is probably calling itself "Cardhu" or something. I don't know what that's about, but just open that up and click the "Update Driver" button. Choose "Browse my computer for driver software" and then "Let me pick from a list of device drivers on my computer". On the next screen, click on the "Have Disk" button and then browse for the .INF file you edited earlier. Then when asked to pick a model, select "Android ADB Interface". You'll probably get warnings about the driver not being signed. Tell the Windows nanny to take a hike and install the driver anyway.

That's what worked for me.