Gengo Girls #90: Immediately Useful

Gengo Girls #90: Immediately Useful

My first thought on writing today’s strip was “Wow, did it really take me 90 pages just to get to a simple idea like ‘I want to’? Maybe I should have covered this earlier”

Then again, most of the stuff up to this point has been pretty important too, so I think all in all I’m OK with the order I’ve been covering material in.

Transcript

言語ガールズ #90

Immediately Useful

Blue: Let’s talk about how to say “I want to do a verb”.

Blue: Start with the polite ます form of the verb. Then replace the ます with たい. Finally add a です to the end to be polite.

Blue: So “I want to read this book” would be 私はこの本を読みたいです

Yellow: Makes sense so far.

Blue: For negative and past tense treat the たい like an adjective.

Blue: For example, “I wanted to read” is 読みたかったです

Blue: That reminds me! I found this great historical fiction book at the library the other day. It’s all about life Victorian England. I can lend it to you if you want…

Yellow:よみたくないです!よみたくないです!

Let’s Program A JavaScript Game 16: Do You Believe In Magic?

Black Magic

In computer programming a “Magic Number” is a number that has been hard coded into your program. Something like “myresults = 42 * myinput”.

This is a bad thing.

When your program needs a specific hard coded number (like the speed of light or the boiling point of water) you should put that number into a well named variable or constant and then use that name throughout your program.

Now let’s take a look at some common magic number problems, why they are bad and how to solve them with named variables.

First magic number problem: They can be hard to understand. Just looking at a number isn’t enough to tell you what it’s for, which can make reading code very hard.

//These magic numbers make it impossible to tell what this program is doing
function estimateFinalPrice(originalPrice){
   return originalPrice * 0.9 * 1.25 + 5.25;
}

//Switching the magic numbers to well named variables makes the function
//easy to understand
function estimateFinalPrice(originalPrice){
   var DISCOUNT = 0.1;
   var TAX = 0.25;
   var SHIPPING = 5.25;
   return originalPrice * (1 – DISCOUNT) * (1 + TAX) + SHIPPING;
}

Second magic number problem: they can be hard to tell apart. Imagine having to update a program with the same number hard coded in multiple places. Do all the numbers represent the same thing, or are they different things that just happen to have the same value? Should you update all the numbers, or only some of them?

//This function has three identical magic numbers... but are they all 
//the same thing?
function getVacationPrice(guests){
   var meals = getMealCost(3*guests);
   var parkPass = getParkCost(3*guests);
   var room = getRoomCost(3*guests);
   return meals + parkPass + room;
}

//Using well named variables make it obvious we are dealing with two different
//numbers that just happen to be the same... for now.
function getVacationPrice(guests){
   var VACATION_DAYS=3;
   var NUMBER_OF_PARKS=3;
   var meals = getMealCost(VACATION_DAYS * guests);
   var parkPass = getParkCost(NUMBER_OF_PARKS * guests);
   var room = getRoomCost(VACATION_DAYS * guests);
   return meals + parkPass + room;
}

Final magic number problem: They are hard to maintain. If one of your magic numbers needs to be updated you have to track down every place it appears in code, make sure it really is the number you think it is and then change it. That’s a lot of work for just doing something like changing tax rates.

Sure, you might think you could just use a find and replace but that’s a really bad idea. Try to replace “7” with “10” and you’ve also accidentally turned “17” into “110”. Or maybe you have two different magic number 7s and you only want to change one of them. Can’t do that with a simple find and replace.

//Good luck maintaining this thing! Forget to update one number and your
//program is broken
function tooMuchMagic(){
   var a = 7 * 7 * 24;
   var b = 7 – 24 * 7;
   return a * b / 7 +24;
}

//This is much better. You can just change one variable definition and 
//everything automatically updates
// Note, this is not real physics (as far as I know)
function noMagic(){
   var WAVELENGTH = 7;
   var FREQUENCY = 24;
   var a = WAVELENGTH * WAVELENGTH * FREQUENCY;
   var b = WAVELENGTH – FREQUENCY * WAVELENGTH;
   return a * b / WAVELENGTH – FREQUENCY;
}

Some Numbers Aren’t Magic

Before you go off and start adding constants to all your code we should admit that there are a couple circumstances where hard coding a number into your program is OK.

The basic rule of thumb is: If the number is small, unlikely to change and it’s obvious what it’s for then hard coding it is OK.

One big example is iterators. You start with a number and then add 1 to it until you reach some final goal like the end of an array. This is a pattern that everybody is familiar with so hard coding values is fine.

// Using a named variable for an iterator is overkill and ugly
var ITERATION_STEP = 1;
var ITERATION_START = 0;
var GOAL = 10;
var iterator = ITERATION_START;
while(iterator < GOAL){
   iterator = iterator + ITERATION_STEP;
}

//We all know how iterators work. Hard coding numbers is just fine
var GOAL = 10;
var iterator = 0;
while (iterator < GOAL){
   iterator = iterator + 1;
}

Other places that hard coded numbers are usually okay:

  • Simple array offsets, like getting position 0 from an array or using -1 to look at the last item.
  • Extremely well known facts like 1000 milliseconds in a second
  • Simple math, like doubling a number or raising something to the second power.
  • Inside math functions. Things like the quadratic equation are well known and don’t change, so hard coding them is fine. You can just type in “4”, no need to come up with a “QUADRATIC_EQUATION_CONSTANT_2” variable.

Time For A Witch Hunt

Now that we’re all up to speed on why magic numbers are bad it’s time to clean up Defrag Cycle. During early development and testing I hard coded a ton of numbers, but now that we’re trying to fine tune the game it’d be really nice to move everything into clean global variables that can be safely tweaked.

This will also have the advantage of making the code easier to read. I’ll probably even be able to get rid of some of my comments. No need to say things like “We’re adding 400 here because that’s how tall the screen is” when we have an obvious variable like “SCREEN_HEIGHT”.

I will include a link to a fully cleaned up version of the code at the end of this article to make up for the fact that I’m not going to show every single change I make.

Let The Hunt Begin

Looking at the top of our file we’re already using well named constants for platform generation, virus generation and the number of points needed to win the game. So there’s a handful of problems we don’t have to worry about.

Scrolling down almost a hundred lines we find our first magic number at the end of the gameLoop function: we hard coded in “50” for the number of milliseconds per frame. Even worse, we hard coded it in two separate places. And worst of all we later use a hard coded “20 frames per second” (the inverse of 50 milliseconds per frame) to calculate the display timer way down in both drawScreen and drawWinScreen.

Let’s fix that by creating a “MILLISECONDS_PER_FRAME” variable and inserting it into all three functions. Now we can speed up and slow down the game by just changing one global variable.

Next problem area is updateGame, and boy is it a problem area! We’ve hard coded how often the player gets points, how fast the player moves, how fast the player jumps, how fast the viruses and platforms move and included several hard copies of things like the size of the screen and the size of the player. There’s a lot here to fix.

First off is creating a FRAMES_PER_POINT constant and using that to calculate how often the player gets points. We’ll also want to use this constant down in the graze calculation area. Remember that we want the graze points to be awarded in between normal points, so instead of checking whether or not the currentFrameCount is evenly divisible by FRAMES_PER_POINT we’re going to check to see if there is a remainder equal to the halfway point between normal frames.

//Award bonus points if the player is grazing a virus
//Offset bonus point award frame from normal award frame
//This makes the point counter update twice as fast during a graze
if(grazeCollision){
   if(currentFrameCount % FRAMES_PER_POINT == Math.floor(FRAMES_PER_POINT/2)){
   currentPoints++;
   }
}

Math.floor is important for those cases where FRAMES_PER_POINT is odd. If FRAMES_PER_POINT is something like “5” the halfway point will be “2.5”. But since currentFrameCount and FRAMES_PER_POINT are both whole numbers you will never get a “2.5” remainder. You have to round down to “2” or the bonus points would never be awarded.

Next up let’s replace all those hard references to movement speeds:

var PLAYER_SPEED = 5; //The player's horizontal movement speed
var PLAYER_JUMP_SPEED = 15; //The upwards speed of the player's jump
var GRAVITY = 1; //How much the player accelerates downward per frame
var TERMINAL_VELOCITY = 15; //The maximum speed the player can fall
var PLATFORM_SPEED = 5; //How fast platforms move to the left
var VIRUS_SPEED = 5; //How fast the enemy viruses' move to the left

Once you’re done inserting all these speed constants into your code we’ll move on to removing hard references to screen and player size:

var SCREEN_HEIGHT = 400;
var SCREEN_WIDTH = 600;
var PLAYER_HEIGHT = 48;
var PLAYER_WIDTH = 75;

We can use the screen variables for drawing the background at the beginning of every draw function, for helping to check when the player is out of boundaries and to check when the player has fallen off the screen. Now we can adjust the size of the game screen by changing two variables instead of having to individually update multiple draw functions and boundary checks.

Player size constants are even more useful and can be used for checking screen boundaries, aligning the player with platforms and calculating hit boxes. For example, our new getFeetHitbox function looks like this:

// Get a 5 pixel tall hitbox all along the bottom of the player sprite.
// Used for detecting when the player has landed on a platform
function getFeetHitbox(xPos, yPos){
   var feetHitbox = new Object();
   feetHitbox.x = xPos;
   feetHitbox.y = yPos+PLAYER_HEIGHT-5;
   feetHitbox.width = PLAYER_WIDTH;
   feetHitbox.height = 5;
   return feetHitbox
}

This function will reliably create a hitbox all along the bottom of the player even if we change the size and shape of the player. Much better than the old version which only worked for player sprites that were exactly 48×75 pixels.

Notice that we still have a hard coded “5” inside this function. We’re going to just leave that there. It is never used outside this function, so maintenance isn’t a concern. Plus the function comment makes it very obvious what the 5 is for. So this one isn’t really a bad magic number.

The other hitbox functions also have local semi-magic numbers that I’m not going to remove for the same reasons.

Moving right along it looks like I’m still hard coding the height of new platforms along with the default spawning location of viruses and platforms. So let’s toss those into constants.

Let’s see… what’s left? Player spawn location is hard coded but that only shows up in one place and is easy to understand so we’ll leave that alone. The game intro, game over and game win screens all have hard coded drawing co-ordinates but I think that’s OK because it’s obvious they’re being used to arrange a specific screen and the co-ordinates are function specific and never reused.

So I guess we’re just about… wait! There’s still one last big problem.

Derived Constants

In our new platform generating code we have a constant “100” that represents how high the player can reasonably jump. We use this to set the minimum possible y coordinate that a new platform can have (it should never be so high that the player can’t jump to it).

You might think this is an easy fix. Just throw in a “MAX_JUMP_HEIGHT=100” and call it a day.

But our calculated safe jump height of 100 only holds true when the player can jump at 15 pixels per frame and falls at one pixel per frame per frame. If jump speed or gravity changes so will the player’s jumping height.

So we can’t just assign a number to the MAX_JUMP_HEIGHT constant. Instead we’re going to need a function that can calculate a max jump height based on the player speed and gravity constants.

It’s not hard to write though. We start by dividing jump speed by gravity to find out how many frames it takes for the player to stop moving upwards. Then we plug that into a basic distance equation, multiply by 0.9 to give the player a little breathing room on his jumps and use that for our constant.

// Calculate how high the player can jump
// Uses basic distance formulate: distance = velocity * time + 1/2 acceleration * time^2
function getMaxJumpHeight(jumpSpeed, gravity){
   var framesOfMovement = jumpSpeed/gravity; //How long until gravity overpowers the jump
   var maxJumpHeight = jumpSpeed * framesOfMovement - gravity/2 * framesOfMovement *framesOfMovement;
   return Math.floor(maxJumpHeight * 0.9); //Give the player a little breathing room
}

And with that we can finally program in our MAX_JUMP_HEIGHT constant

var MAX_JUMP_HEIGHT = getMaxJumpHeight(PLAYER_JUMP_SPEED, GRAVITY);

And with that we can slay our last magic number

//Platform can't be higher a jump from the current platform or 100 pixels from top of screen
var minPossibleHeight = Math.max(platforms[platforms.length-2].y - MAX_JUMP_HEIGHT, 100);

I’ll be keeping that other 100 since the comment makes it obvious what it’s for and it’s only ever used in this line.

See All The Changes

Here’s the latest copy of the magic free code.

With that out of the way we can start working on the finishing touches for the game: Music, sound effects and special effects.

Gengo Girls #89: DO NOT WANT

Gengo Girls #89: DO NOT WANT

It’s always kind of fun to look at how different languages approach the same idea. In English it’s “I want an X” but in Japanese it’s “X is wanted by me”. It works out to the same meaning in the end but it can take a little work to get used to the unusual (to us Americans) word order.

Vocabulary

欲しい = ほしい = wanted

Transcript

言語ガールズ #89

DO NOT WANT

Blue: Another useful and pattern is 私は X が欲しいです. It means “I want an X”.

Blue: The “X” has to be a noun. There are different rules for saying you want to do a verb.

Yellow: So I could say: I want a cake.

Blue: 私はケーキが欲しいです.

Yellow: But I couldn’t say: I want to eat a cake.

Blue: Since 欲しい is an adjective you have to conjugate the 欲しい, not the です, when talking about the past or saying “I do not want”.

Yellow: 欲しかったです. Not 欲しいでした.

Blue: So, is there anything you want to ask me?

Yellow: That’s a trick question, isn’t it!? Since “want to ask” would be wanting a verb and 欲しい only works for nouns!

Blue: I just wanted to know if you had any questions…

Gengo Girls #88: Speak Softly And Carry A Big Katana?

Gengo Girls #88: Speak Softly And Carry A Big Katana?

Japanese culture puts a strong value on avoiding direct confrontation with your peers. And since phrases like “I hate X” can cause conflict with people who happen to like X it’s better to just say “I don’t like X very much”. It gets your point across while still being mild enough to not rub other people the wrong way.

After all, the last thing you want is to be known as the foreigner whose first impression involved telling everybody how much he hates the Japanese subway system. I don’t care how motion sick you get, the proper phrasing is “I don’t like riding the subway very much but the system itself is very impressive and high tech”.

Vocabulary

嫌い = きらい = hated, disliked

Transcript

言語ガールズ #88

Speak Softly And Carry A Big Katana?

Blue: and patterns can be reversed by negatively conjugating the verb.

Blue: “I don’t have a car” is 私は車がありません
Yellow: Or more casually: 車がない

Blue: “I don’t like books” is 私は本が好きではありません

Yellow: Or more casually: 好きじゃない

Yellow: Hey, isn’t there an adjective that means “disliked or hated”?

Yellow: Can’t I say “私は本が嫌いです”?

Blue: You could… but 嫌い is a pretty strong word.

Blue: In general the Japanese prefer subtle language over blunt statements.

Yellow: I guess you would expect subtlety from the language of ninjas…

Blue: That’s… not quite right.

Gengo Girls #87: Who You Gonna Call?

Gengo Girls #87: Who You Gonna Call?

This pattern is also useful for talking about things you “have” but don’t necessarily “own”, like family members and friends. But phrasing it as “possessions” let me use that lame ghost joke and without lame jokes Gengo Girls is no different from any other old textbook.

Transcript

言語ガールズ #87

Who You Gonna Call?

Blue: and also work together for talking about possessions.

Yellow: Possession? Like ghosts and demons?

Blue: I mean like things you have. “I have a car” or “I have a dog.”

Blue: The pattern for “X has a Y” is “X Y が いる/ある”

Yellow: Is that the same いる and ある we use for talking about locations and existing?

Blue: Yes it is. Which one you use depends on whether Y is alive or not.

Blue: “I have a car” would be “私は車があります”

Yellow: It’s kind of like saying: “There is a car that exists and has a connection to the topic of me.”

Blue: Kind of. But it sounds unnatural to translate it like that.

Yellow: And the car is haunted, right?

Blue: Let me start over from the beginning. and are useful for talking about ownership…

Gengo Girls #86: Like… Or Like Like?

Like... Or Like Like?

“suki” is a semi-common word in Japanese media. The romantic version of “suki” obviously shows up in just about every romantic drama or comedy in existence. But the non-romantic version gets plenty of use too and even in non-romance works it’s pretty common to hear children “suki” their parents or for people to talk about all the hobbies they “suki”.

Vocabulary

好き = すき = liked, loved (pronounced “ski”, not “su-ki”)

Transcript

言語ガールズ #86

Like… Or Like Like?

Blue: In some cases you can use and together to create one sentence with two different but related topics.

Blue: For example, the sentence pattern for “I like X” is 私はXが好きです.

Yellow: So “I like books” must be 私は本が好きです

Blue: The “私は” lets us know that the main theme of the sentence is “me”.

Blue: The “本が” tells us that there is a link between topic #1, me, and topic #2, books.

Yellow: And the “好きです” tells us that the link is that you like them!

Blue: But be careful! Using 好き to talk about other people can be interpreted as a romantic “I love them” instead of a friendly “I like them”.

Yellow: Romantic comedy misunderstandings here we come!

Gengo Girls #85: Grammarist

Gengo Girls #85: Grammarist

With a little research you can find tons of articles on all the differences between and , but as a beginner you really just need to know that they do almost the same thing but that is slightly more common. That’s enough to let you get by until you have the time and experience to really look into the details. No need to overwhelm yourself all at once.

Transcript

言語ガールズ #85

Grammarist

Blue: isn’t the only subject marker in 日本語. You can also use .

Yellow: What’s the difference?

Blue: It’s complicated… but in general you use when you want to put extra focus on the subject of the sentence.

Yellow: As a grammar egalitarian I object to one part of speech getting more attention than the rest.

Blue: If I was talking about my birthday I might say 私はケーキを食べました.

Yellow: I ate a cake.

Blue: The subject and verb get equal focus. We’re talking about me and what I did.

Blue: But if some asked me “Who ate that cake?” I would answer 私がケーキを食べました.

Blue: The focus is admitting that “Who” was . The verb is almost just a background detail.

Gengo Girls #84: Gone Tomorrow

Gengo Girls #84: Gone Tomorrow

I’ve heard that many Japanese people believe that they are the only country to have all four seasons and are surprised when foreigners tell them that countries like America also have a distinct spring, summer, fall and winter.

No idea why they think this way. Probably just one of those little cultural myths that everybody grows up hearing and never bothers to think about. “Only Japan has four seasons. Every other country is too hot, cold, wet or dry to experience all four seasons properly.”

Vocabulary

= はる = spring

= なつ = summer

= あき = fall

= ふゆ = winter

寒い = さむい = cold

Transcript

言語ガールズ #84

Gone Tomorrow

Blue: The negative casual form of ある is ない. That means the negative past tense casual is なかった.

Yellow: One of these days we’ll run out of irregular verbs and what a happy day it will be.

Yellow: So now what are we going to talk about?

Blue: How about a quick vocabulary lesson?

Blue: Here are the words for the four seasons:

Blue: 日本 is in the right part of the planet to have all four seasons. It’s not like those tropical islands where it’s always warm.

Yellow: Always warm actually sounds pretty good. 冬は寒いですよ!

Gengo Girls #83: Lost and Found

Gengo Girls #83: Lost and Found

While “iru” and “aru” are probably most important for talking about locations they can be pretty useful all on their own too. Want to say “We have a problem?” Use “mondai ha aru” to say “A problem exists / There is a problem.”

Also, if anyone is actually curious I’m pretty sure you use “iru” when talking about zombies because they move around as if they were alive. This is also true for other semi-alive things like robots.

Transcript

言語ガールズ #83

Lost and Found

Blue: The verbs いる and ある both mean the same thing: To exist.

Blue: You use いる for living things and ある for almost everything else.

Blue: You can use them with to talk about the locations of people and objects.

Blue: The pattern for “X is at place Y” is “XYに いる\ある”

Blue: “I am at the library” would be “私は図書館にいます”.

Yellow: Wouldn’t that literally mean “I exist at the library”.

Blue: Literal translations aren’t always the best.

Yellow: One last question: Should I use いる or ある for talking about zombies?

Blue: Why can’t you ever have a normal grammar question?

Gengo Girls #82: Overly Ambitious Goal Setting

Gengo Girls #82: Overly Ambitious Goal Setting

I could go on and on about all the different ways to use “ni”… but I’m not going to. The two broad uses we’ve covered here (marking locations and marking the target/goal of verbs) are good enough for a beginner. Just don’t be surprised if you see a “ni” being used in a slightly different way every once in a while.

Vocabulary

なる = to become

病気 = びょうき = sick

Transcript

言語ガールズ #82

Overly Ambitious Goal Setting

Blue: can also be used to mark the goal or target of an action.

Blue: For example, “友達 に なります” means “To become friends”.

Yellow: I think I get it.

Yellow: The action is “become”. What are we becoming? Friends.

Blue: It doesn’t have to be a purposeful goal either.

Blue: 病気になります means “To become sick” even though most people don’t purposefully set a goal of getting sick.

Blue: So if you see a that isn’t marking a location it’s probably marking a goal or target.

Yellow: Come on , leave some work for the rest of the prepositions.