Gengo Girls #94: Anybody Got A Medkit?

Gengo Girls #94: Anybody Got A  Medkit?

One popular Japanese superstition claims that “Idiots can’t catch colds”. Don’t know where it came from but it provides a great setup for a lot of friendly teasing (Gee Tanaka-san, you’re the only one in the office that hasn’t gotten sick this winter. I wonder why? Ha ha ha).

Although as a beginner you probably shouldn’t try and crack any jokes like that. Telling a joke without offending anyone is really hard in a foreign language and the last thing you want to do is call your boss an “idiot” and have him not laugh back. So for now just stick to boring formal Japanese and leave the jokes to the natives.

Vocabulary

あなた = you (formal)

病気 = びょうき = sick

風 = かぜ = wind

風邪 = かぜ = common cold

Transcript

言語ガールズ #94

Anybody Got A Medkit?

Yellow: I don’t feel so good…

Blue: あなたは病気ですか

Yellow: Huh?

Blue: I asked if you were sick.

Yellow: Maybe a little…

Blue: That reminds me! Did you know that the 日本語 words for “wind” and the “common cold” are both pronounced かぜ and share a kanji?

Blue: Remember it this way: If you stay out in the too long you’ll catch a 風邪.

Yellow: Are you saying… words?

Blue: I think you need to go see the nurse.

Gengo Girls #93: Bait And Switch

Gengo Girls #93: Bait And Switch

01001001 00100000 01100100 01101111 01101110 01011100 00100110 00100011 00110000 00110011 00111001 00111011 01110100 00100000 01110111 01100001 01101110 01110100 00100000 01110100 01101111 00100000 01110011 01110100 01110101 01100100 01111001 00101110 00100000 01001001 00100000 01110111 01100001 01101110 01110100 00100000 01110100 01101111 00100000 01110000 01101100 01100001 01111001 00100001

Transcript

言語ガールズ #93

Bait And Switch

Yellow: Let’s do something different today.

Yellow: I don’t want to study. I want to play!

Blue: Only if you can translate that sentence…

Yellow: 私は勉強したくありません。 遊びたいです。

Blue: Very good.

Blue: But you didn’t let me finish.

Blue: Only if you can translate that sentence… into binary code.

Yellow: That’s not fair!

Blue: It’s your fault for not noticing the “…” in panel one.

Gengo Girls #92: Window Stealing

Gengo Girls #92: Window Stealing

It’s really easy to “steal” a short book by finding a corner in the store and then reading the whole thing before anyone notices. It’s a little bit harder with longer books. And I really don’t recommend trying to memorize an entire dictionary in stealth mode.

More seriously, notice that the word for money, “okane” has an honorific “o” at the beginning. Like I mentioned back in strip 53 there are certain words that almost always have a polite honorific attached to them and “okane” is one of them.

Vocabulary

買う = かう = to buy

ゲーム = game

お金 = おかね = money

 

Transcript

言語ガールズ #92

Window Stealing

Yellow: こにちは! What are you doing here at the mall?

Blue: 本を買いました

Blue: What about you?

Yellow: 新しいゲームがあります!

Blue: 買いましたか

Yellow: いいえ。私はお金がありません

Blue: Why would you come to the mall with no money?

Yellow: I played the game for three hours on the store’s demo system before they asked me to leave.

Gengo Girls #91: Who Cares What He Wants?

Gengo Girls #91: Who Cares What He Wants?

So “hoshii” and “-tai” can’t be used in third person. And it’s pretty obvious they can be used in first person (since most of our examples were done that way). But what might be less obvious is that they can be used in second person questions. If you want to ask someone “What do you want?” or “Do you want to do X?” you can use “hoshii” and “-tai”.

You may not really know what the other person wants, but you can ask them.

Of course, even if someone tells you what they want there is no way to be sure they were telling the truth so you still can’t use “hoshii” and “-tai” to talk about their answer.

Transcript

言語ガールズ #91

Who Cares What He Wants?

Blue: 欲しい and the –たい ending have an important restriction: They can’t be used in third person.

Yellow: You mean I’m not allowed to say things like “My dad wants a new car”?

Blue: Not with 欲しい and –たい.

Yellow: How come?

Blue: The basic idea is that you can never know for sure what other people want.

Yellow: What if I’m pretty sure my dad wants a new car?

Blue: Later on we’ll learn some grammar that lets you say “I think my dad wants a new car” or “My dad says he wants a new car”.

Yellow: What if I was psychic? Then I could know for sure what other people want.

Blue: 日本語 wasn’t really developed with psychics in mind.

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!