ID:1783366
 
Lesson #2 :: Elegant weapons for a more... civilized age.

Lesson #1 | Lesson #2

In the previous instalment of the Webclient Tutorial series, we learned how to get a very basic, barebones interface up in the webclient as well as how to actually run a webclient game. In this next lesson we'll talk about two big ideas: byondclasses and JSON. To give you a brief overview before we delve any further, a "byondclass" is simply a type of control that we can use in our interface markup. They help organize our interface into objects that have their own properties, functions, etc. For example, "output" and "map" are byondclasses we're familiar with from the old dmf format.

JSON is a more advanced but fundamental topic that we'll have to tackle before anything else, as defining a new byondclass requires you to know how a JavaScript anonymous object works. Basically, JSON is just a format that we'll use to store and transfer data.

JSON (JavaScript Object Notation)


We use JSON heavily when writing code in JavaScript, and consequently, in defining behaviors for our byondclasses. If by now you don't already know some basic JavaScript I highly, highly urge you to take a few basic courses over at CodeAcademy or W3 Schools. For those that wish not to, or are comfortable progressing; let's start with a very basic object in JavaScript.

{
message: "Hello Web!"
}

/*
Whitespace is ignored, so it can also be written in a single line:
*/

{message:"Hello Web!"}

The first thing to note are the opening and closing brackets. In JavaScript, they are the tokens used to let the code know that we're starting to make a new object. You can think of it as serving the same purpose as indentation in DM. What this code is saying is that inside the object we're creating there is a variable called message and it contains "Hello Web!". If we want to read the variable, then we can simply do object.message to retrieve it. Alternatively you can treat the object as an associative container and do object["message"]. Whatever works best for you.

Now let's define a list in JSON:

["Apple", "Orange", "Tomato", "Grape"]

It's pretty simple, and can be loosely translated to list("Apple", "Orange", "Tomato", "Grape") in DM. A list type is dynamically-indexed, meaning you don't need to worry about static array lengths. An object in this array be retrieved by performing array[index]. Be careful! Outside of BYOND most languages will start arrays at 0. Therefore, if you want to get "Orange", you won't look in index 2. Instead, you'd look at index 1 since index[0] = "Apple". This may confuse and disorient you, but as long as you remember to subtract your indexes by 1, you'll be fine.

Let's get really tricky and wrap this all together into one big object:

var Bob = {
name: "Bob",
age: 37,
gender: "male",

employment: {
company: "Professional Business Inc.",
salary: 40000,
boss: "Chief Executive Rodger Smith"
},

thoughts: [
"I need to go to the store.",
"What's the wife cooking this evening?",
"Videogames are fun."
]
};

This object is defining a person (variable name Bob) with the name of "Bob", whose age is 37 and gender is "male". But you'll also notice that the employment and thoughts members are complex containers, not just values. They can be thought of as sub-objects and arrays within the main object, kind of like a player's inventory!

Bob.employment contains information about his company, salary, and his boss. Bob.thoughts is a small array of random thoughts on Bob's mind. In JSON objects can be infinitely-complex. Arrays can contain objects, objects can contain many layers of internal objects, and etc. JSON is really just a neat way of organizing data anonymously - that is, without requiring the definition of a class beforehand.

Before proceeding to the next section, try to:
  • Define an item object complete with fields for a name, weight, description, etc.
  • Use those fields to organize a bunch of random objects into a single JSON array, so you have an array of objects.
  • Create a player object with some random members, and include that array as part of the player's "inventory" member.


Your First Byondclass


Next up, we'll tackle creating our very own byondclass. A byondclass can be used for anything in a UI, from just organizing internal data to actually displaying information. For the most part, we'll be using it to create custom UI elements.

For our example environment, let's create a byondclass that is:
  • Invisible until called upon.
  • Overlays everything on the screen.
  • Can have its text set via DM code.
  • Can display the player's icon.
  • Can inform the player when a button has been clicked.


I'm basically describing a custom alert popup that displays text, an icon, and a button to close it with some confirmation on the server-end that the client closed the screen. For this, we'll create a new file called first_byondclass.dms [+]. In this file, we'll add the following code:

<!-- I'm an HTML comment! Just so you know, if you see me around again. Don't actually include me in your code. -->

<byondclass name="firstclass">

<!-- Our CSS styling goes here -->

<style>
</style>

<!-- Our JavaScript code goes here -->

<script>
</script>

<div id="content" class="content"></div> <!-- The div that will be containing our text. -->
<div id="button" class="button">Okay</div> <!-- The div representing our confirmation button. -->

</byondclass>


Anything in the byondclass tags can be considered as part of a separate "document" which contains information about that specific class. Meaning whenever we actually use this class, all code within will be included along with it. Inside the class we have style and script tags. We also have some stray divs, which help divide our control into separate nodes. We'll need them when we want to individually update one or both with separate text.

Within the script tags, we'll start to include our basic code. Everything within script must be in the form of a single JavaScript object. Meaning it will always begin and end with brackets:

<script>
{
fn: {

}
}
</script>

Here we're defining a single object with an fn member. This is one of the few key members in a byondclass' code structure. We'll use it to define code that can be called via DM. For instance, we'll now define a function called whenever DM tries to output() to it:

<script>
{
fn: {
output: function(obj) {
if(obj.hasOwnProperty("text")) {
this.ui.content.innerHTML = obj.text;
}
}
}
}
</script>

What we have now is an output member containing a function. JS objects can also contain functions much like BYOND objects! This function accepts the argument obj which can but won't necessarily always contain the text member. So obj is, itself, a JSON object. The hasOwnProperty() function simply makes sure the object has text before moving onto the next step:

Setting the text to the "content" div to obj's text data. Previously we defined a div by the id of "content", which can be pointed to within the scope of our entire object through this.ui, which is a container of all named items in the byondclass.

Configuring your byondclass


Next up, we'll add some fun styling to our element:

<style>
#firstclass {
width: 200px;
height: 150px;

position: absolute;
left: calc(50% - 200px/2);
top: calc(50% - 150px/2);

background: #fff;
box-shadow: 0px 0px 25px #fff;
border-radius: 15px;

padding: 15px;
text-align: center;
}

.button {
width: 80px;
height: 25px;

margin: auto;
border: 1px solid grey;
background: #BABABA;
}
</style>

This gives our element some nice definition, and also begins to flex some muscles that would be ostensibly impossible or extremely difficult to do on DreamSeeker. You'll see what I mean in a bit.

Next, let's actually add the byondclass to index.dms. It doesn't matter where, as long as it's under the topmost scope.
<div id="firstclass" byondclass="firstclass" skinparams="is-visible=false"></div>


But what does matter is that the fact that we're initializing the byondclass with is-visible set to "false". We don't want it to be visible by default, only when we need it. Next, we add a macro, doesn't matter what key (remember Lesson #1) pointing to a "showsubprompt" verb which calls the following code:

verb/showsubprompt()
winset(src, "firstclass", "is-visible=true")
src << output("I'm a prompt!", "firstclass")


Compile it and run, and you should get the following result: [+].


Congratulations, we've got our first custom byondclass psuedoprompt up and running! Unfortunately there's no way to close it, and we haven't yet fulfilled the previously-defined requirement of being able to communicate back with the server, and display the player's sprite. We'll finish our control and delve into the more complex tasks in Lesson #3! Stay tuned.
Very nice, keep up the good work!
Another excellent tutorial. This really should help a lot of users who want to make their own class.

A note on styles: Wherever you use this class in your skin (e.g., <div id="mydiv" byondclass="firstclass"></div>), it will be given a CSS class of "byond_firstclass" when it's initialized. All control divs get "byond_[classname]" as a class. Therefore if all your styles in the <style> block start with .byond_firstclass they will impact only controls of this type.
Moving fast through these lessons. Very nice work.
I Love you for writting this! Cant wait for #3
Appreciate the tutorials. You've sort of inspired me to look into learning Javascript. Thanks :)
Perfect! I'm really looking forward to seeing everyone take full advantage of the web client after you're done.
Been trying to get a lesson out every single week but sadly I've hit a bit of time constraints (accompanied by a bit of procrastination on my part).

Thanks for the kind words, though, everyone!
These tutorials aren't dead! I've just found it exceptionally hard to find the time and motivation to write one in between the very limited free time I have. I'll definitely get around to it, though.

The next section, as alluded, will explain how to implement jQuery into your projects, as well as communicating back tot he server from the client-end.
Hi Doohl,

Just wanted to say these are awesomely written with solid clean and concise content. I eagerly await more!
Only 8 people interested in web client tutorials?
I'm interested too. I guarantee there's quite a few more lurkers appreciating Doohl from the shadows.
In response to Amad2
I'm aware people want more of these tutorials :) I just haven't had the time or motivation honestly to continue on with Lesson #3. I'm sure not a lot of people want to put in the effort to learn the small bit of Javascript that'll be required for Lesson #3. After all, if you're learning Javascript why not scrap BYOND and just make a native ORPG with node.js and canvas rendering?

The past few months have been spent being super busy with college and Severed World.

I'll probably continue these at some point, but I'm not sure when. Hopefully what little I've posted has at least helped people learn on their own.
In response to Doohl
Doohl wrote:
I'm aware people want more of these tutorials :) I just haven't had the time or motivation honestly to continue on with Lesson #3. I'm sure not a lot of people want to put in the effort to learn the small bit of Javascript that'll be required for Lesson #3. After all, if you're learning Javascript why not scrap BYOND and just make a native ORPG with node.js and canvas rendering?

The past few months have been spent being super busy with college and Severed World.

I'll probably continue these at some point, but I'm not sure when. Hopefully what little I've posted has at least helped people learn on their own.

It has been helpful and I appreciate it. College (first!) and one of the most professional looking games made with Byond are definitely what you should be focusing on. But if at some point you decide you want to continue the tutorials, I bet there are more people willing to put in the effort to learn that small bit of JS than you think ;)

Thanks and good luck.
Next lesson should be a guide to designing your own interface
Doohl! Do I have to pay you to finish at LEAST the next lesson (arguably the most important!).

Edit:
I'm currently passing everything back through to Topic() as I haven't a scooby on other ,maybe better ways of doing it.
Something I'm going to cover in Lesson #3 is how to include and use jQuery in your project. Some people seem to be very confused as to how you properly include and use it in your project, which is understandable since the process requires you to do a bit of a hack; it's definitely not straightforward, which is one of the glaring faults of the webclient itself.
Please, D: dont forget about us!
:S we need a tutorial like these to make a decent use of webclient :'(
Please, more tutorials on the web client, Doohl! This series is extremely importaint to getting developers using the web client to the fullest potential.
Please Doohl!! one more lesson!!!!!!!!!!

I feel like i'm finally making heads and tails of this!