In the recent advances in the BYOND programming system, there has been a slew of new and interesting features. One of those features is screen objects. "What is a screen object?", you might ask. Well simply put, it's a visual effect that stays static on your screen, while never leaving your view. It's mostly used for HUD (Heads-Up-Display) systems, but it's also used for things such as graphical interfaces and verb/statpanel replacement.
First, we'll start by getting you familiar with the basic variables used in screen objects: client.screen and atom.screen_loc.
This is the list that contains all screen objects a client owns. All objects you want to be displayed on your screen must be added to this list.
This is the variable that sets where on the screen an atom (area, turf, obj, mob) is placed. The numbers depend on what you're using for client.view; if the player sees a map that's 5 turfs wide and 9 high, then the upper right corner will be "5,9". The lower left is always "1,1".
Okay, now let's get started. First off let's create an object:
screenobj1 //this is the type-path of the object
icon = 'someicon.dmi' //this is the name of the icon used (Note: You'll have to make some icons)
icon_state = "screen object 1" //name of the individual graphic contained in the icon file
screen_loc = "1,1" //sets the object's screen_loc var to 1,1, which is the first tile on the first row of the viewport
New(client/C) //when the object is created, I'll pass client/C as an argument so I don't have to define it as a var
C.screen += src //adds the object to the client's screen list
That was only the first half of adding the object to the screen. Now you have to create the object for its New() proc to be called.
client/New()//when a new client is created (called when a person with a key connects to the game)
..() //calls the parent type, so the proc follows through with its default actions (connecting to a mob)
new/obj/screenobj1(src) //creates the object we just defined, and calls its New() proc, executing everything under obj/screenobj1/New().
Easier than most people think, really. That's all there is to creating and adding an object to the screen.
Now let's go on to something else. More than one object is just about as easy as creating one alone.
screenobjects //parent type
icon = 'screen.dmi' //sets the icon for all the children to this type
one //child type
icon_state = "one" //sets the icon_state to the graphic named "one" in the "screen.dmi" icon
screen_loc = "1,1"
icon_state = "two"
screen_loc = "2,1" //second tile in the viewport
New(client/C) //when any child is created
C.screen += src
for(var/obj/O in typesof(/obj/screen)-/obj/screen) //a nifty trick to use when adding a lot of things under the same type, looping over every object that's a subclass of /obj/screen
new O(src) //add them all... saves a lot of work
Now, if you have a map, a mob, and some turfs on the map, you should be able to see two different objects on your screen (if you set the icons right). Now notice how they move along with you. Neat, huh?
Adding and removing screen objects at runtime
To add an object to client.screen at runtime, you must have a screen_loc defined for it before going on. Now you can add it using a simple verb:
new/obj/screen/three(usr.client) //it's usr.client instead of usr because you're not adding it to the player's mob -- you're adding it to the player's client. (Make sure you go back and define obj/screen/three before doing this!)
Now, to remove it.
for(var/obj/screen/three/T in usr.client.screen) //loop over all the objects with the type /obj/screen/three in the usr's client's screen list.
del(T) //delete them as they're found
Adding text, numbers, and other static items (such as inventory) is a bit more advanced, but I'm not going to go into it here; if you want to know more about doing this, there are a few demos/libraries/tutorials on the BYOND Hub (see the list below).
AbyssDragon's PopupInventory [Note: this link is no longer active -- Ed.]
Code tree organization
One of the least touched-on subjects in DM is organization of your code. This is helpful if you're just starting and need your code to be easy to read, or if you're releasing the code for others to read. There are many methods of making your code look "nice".
One of the most common ways to keep track of your code is comments. "What's a comment?" you might ask. Well, it's simply text that is compiled with your code, but ignored by the compiler (Dream Maker). This allows you to write about what your code does without affecting its execution.
A single-line comment is one line and ONLY one line of commented code. This means when you create a newline, the comment is ended. These types of comments are set off by the "//" operation:
verb //this is a comment; this text does not affect anything else on this line
usr << "Something!"
Multi-line comments are commonly used to describe long blocks of code without trying to fit it all on one line. These are opened by the "/*" characters, and closed with "*/".
comment; all of this text is read as a comment, and not code.
Most times when you see something like:
usr << "Something"
You get a cluttered feeling about the code, and it usually takes longer to read. This section will teach you how to spread out your code and make it look neat.
Code that branches out into numerous subsections is referred to as a tree. Here's an example of a code tree. Instead of packing several nodes into a line with slashes, I give each node its own indent level:
icon = 'icons.dmi'
verb //the "verb" branch
usr << "Something"
usr << "Something else"
player //we're defining "player" as a specific type of mob, which makes "player" a "subtype", "subclass", or "child" of the mob type.
icon = 'player.dmi'
Most "neat" programmers use "whitespace" in their code. Technically "whitespace" is anything that isn't represented by a character -- tabs, spaces, and line breaks. BYOND automatically enforces the use of tabs for code organization, but I also find it useful to use double line-breaks that separate the code into readable form and make it easier on the eyes. (I used this technique in my last example.)
That's about it for this installment of Nadrew's How-To's. Thanks for reading!