Alright! Here we go...
function TextTyper()
{
this.msg = "";
this.loc = 0;
this.wind = GetSystemWindowStyle();
this.font = GetSystemFont();
this.time = 0;
}
Alright, all pretty obvious and self-explanatory. And checking the Wiki's OOP primer, I can see that this actually isn't creating a function, despite JS's wording. This is actually a prototype. Which, actually, is a term I don't prefer. I prefer class, for some reason. Archetype would be better than both, but prototype sounds like a primitive version of something, whereas archetype sounds like the template for something, which is what a class/prototype is.
TextTyper.prototype.type = function(msg) {
this.msg = msg;
this.loc = 0;
this.time = GetTime();
}
Okay, so this uses the prototype dot operator thingy to create a method called type for TextTyper. Interesting syntax -- Object.prototype.method = function(stuff). I'm used to "function nameOfFunction(stuff) {do this}." Seeing "function(stuff)," like just using the generic term "function" instead of a name, is kinda weird, but I get it.
Now wait. We obviously set local(?) variables here (I've only ever heard the term "global variable" so I presume the opposite is called local), but they're the same as in the TextTyper class declaration above. So are these different? Is TextTyper.msg different from TextTyper.type.msg? If so, why did we have to declare those properties in TextTyper? If not, why do we have to declare them here?
Either way, I find it interesting that all TextTyper.type does is set a message, location and time. Even though we use TextTyper.type("whatever") later to print whatever, TextTyper.type isn't where we have our actual typing-out code.
TextTyper.prototype.update = function() {
this.wind.drawWindow(16, 16, 256, 128);
this.font.drawTextBox(16, 16, 256, 128, 0, this.msg.substr(0, this.loc));
Okay see, now I'm confused. Because we gave TextTyper a msg, loc and time using 'this.', and then TextTyper.type had a repeat of those. But here, TextTyper.update just uses TextTyper's wind and font. So why was it necessary to re-do .msg, .loc and .time in TextTyper.type but not re-do .wind and .draw here?
Oh, but I see why this code constantly draws a window on the screen -- TextTyper.update is constantly running via SetRenderScript, and here, it's constantly drawing a window. Technically it's also constantly drawing text to that window, but if msg = "", no text will be drawn.
if (this.time + 25 < GetTime()) {
if (this.loc < this.msg.length) this.loc++;
this.time = GetTime();
}
}
I'm uncomfortable with nested ifs (just 'cause I've never done them myself), but I'll try to marshall through. Okay, TextTyper.type GetTime()'d for us, so when this piece of code first starts, this.time will equal...whatever time Sphere is counting forward from. The exact number doesn't matter.
"if (this.time + 25 < GetTime())"
Okay, so presuming SetRenderScript is running our code once per millisecond, when the code very first gets here, this.time --
OHH! I get it! In the initial TextTyper object declaration at the beginning, we were initializing the local variables. Then TextTyper.type modifies them. TextTyper.update doesn't need to mess with .wind or .draw because they don't need modified! Sorry; writing in a stream of consciousness here. Where was I?
Yeah, when the code very first gets to "if (this.time + 25 < GetTime())," the new GetTime() here will only be like one millisecond past this.time. Adding that +25 delays the code inside the if by 25 milliseconds so it doesn't print as fast.
Hmm. Here's something I don't understand, though. The GetTime() here isn't being stored in a variable. Every time TextTyper.update runs, it should be Getting a new Time...which should always be just one millisecond after this.time. Oh, wait, no. I just ran a test in Sphere -- GetTime constantly counts upward. Nevermind.
Anyway, when I write up my own text typer, I'll make the +25 a variable. this.txtspd, for instance, so that the speed can be modulated by the end-user. Heh, this offers some insight into videogames I've played that let you alter the text writing speed, 1-9 or 1-100 or something, and higher is typically slower. That's counter-intuitive, but makes sense; the higher this.txtspd, the more a millisecond delay and the slower the text types. Since most people who play videogames aren't coders, though, they probably should've flipped the visual representation of the text speed option slider, so it'd make sense to msot people (higher = faster).
Oh, and the inside of the first if is pretty self-explanatory -- it prints msg from 0 to loc, then increments loc, and Gets a new Time in this.time.
var typer = new TextTyper();
function game()
{
typer.type("Hello, how are you doing? This is a fine day, have fun!");
SetRenderScript("typer.update();");
MapEngine("test.rmp", 60);
}
Oh. That's it.
Wow, that was pretty easy to understand (my little hiccup with variable declarations notwithstanding).
Hmm again. Something I don't understand, though maybe I do. Why do we have to make a new TextTyper and call it typer? Why can't we just do TextTyper.type("Hello, how are you doing? This is a fine day, have fun!");?
I mean, in a general sense, I can understand doing this. If we had a class for PlayerCharacters, for instance, obviously you'd "player1 = new PlayerCharacter; player2 = new PlayerCharacter;" etc.
I suppose I don't understand why TextTyper has to be a class. Or rather, why we have to make an instance of it, why we can't just use it itself. Maybe if an instance could have a different window color or text speed or what have you. But no, those could be modulated with variables. So yeah, I kinda don't get why this has to be done as an object. Other than the fact that you can't append methods to regular functions.
Which brings me to a simple question. Does everything need to be done with classes and objects and such? Like, using my Gauntlet-esque game as an example, consider treasure. All it does is, if you step on it, it plays a sound effect, adds to your Score, and disappears. So, the code might be...
function TreasureBox(); {
LoudSound(treasureget.midi);
Sound.play(false); // Not sure if this is how Sounds work, but you get the idea.
PlayerScore += 100;
DeleteSelf(); // Or whatever. I dunno how to erase entities.
}
And then in the treasure entity's On Activate Touch, just call TreasureBox();
I can't think of any way or reason to involve objects here. Unless you were to have different kinds of treasure that give different Score values, then obviously a simple object would be nice, 'cause then...wait, no. You could just modify my above code to...
function TreasureBox(amount); {
LoudSound(treasureget.midi);
Sound.play(false);
PlayerScore += amount;
DeleteSelf();
}
Yeah. So I can't see any reason to do this as an object/class. Other than to avoid having any raw functions in your code, to have everything be a class. Is there some reason to do the above treasure code in an OOP way? Would it be more efficient?
I learned a lot from your code example, though, Radnen. Thanks again. Next post, I'll try cooking up some simple OOP myself.