ID:35771
 
A BYONDscape Classic!


Screen objects

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.

client.screen

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.

atom.screen_loc

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:

obj
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.

obj
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"

two

icon_state = "two"

screen_loc = "2,1" //second tile in the viewport

New(client/C) //when any child is created

C.screen += src

client/New()

..()

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:

mob
verb
AddobjThree()
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.

mob
verb
RemoveobjThree()
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).

Helpful links

My HUD demo

Dantom's screen builder

Shadowdarke's sd_text

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.

Single-line comments

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:

mob
verb //this is a comment; this text does not affect anything else on this line
someverb()
usr << "Something!"

Multi-line comments

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 "*/".

/*This
is a
multi-line
comment; all of this text is read as a comment, and not code.
*/

Code organization

Most times when you see something like:

mob/verb/something() 
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:

mob
icon = 'icons.dmi'

verb //the "verb" branch

someverb()

usr << "Something"

someotherverb()

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!