Learning BYOND, Day 7: All About Image

Seriously, today really was all about the image for me… the BYOND image object and how it is used, that is. It turned out to be a rather long and agonizing day: I wish I had known now what I did when I started. Sit back, read, and enjoy the butter without the churning I did today.

The image object refers to an image that is not actually part of the game world, but rather is a custom image specifically made to be drawn on the screen of any specifically specified users’ client.  Such objects have many potential applications, such presenting a custom GUI or applying special effects beyond what the world engine is normally capable.

The official instructions on images is quite short. It’s not mentioned at all in the client chapter and (as we’re about to discover) that’s a major omission. The Dream Maker help mechanic and BYOND developer community are the best reference I’m aware of for image objects.

The brevity of the help is probably because image objects are actually pretty easy to use… provided you stick to one image object reference variable at a time: However, I wasn’t content with that: I wanted to do a whole image list at a time. There lay madness.

Finally, I figured out the one thing they don’t flat out tell you (unless you very carefully read the BYOND dream maker help in the “image var (client)” section):

“The key to displaying images is a specially handled client object list. The “client.images” variable is directly called by the hardcode every update to display any and all image objects involved for that client.”

Edit (Sept 8th, 08): Originally, I wrote this Blog entry with an understanding that client.images was very arbitrarily handled for a list.  This is because, in my code dabbling, it exhibited unusual behavior.  Trying to call image.len (to get the length of the image list) did not work, nor did using a “for variable in images” call.

Zac pointed out in the comments that actually you can do this without trouble, leading me to wonder if perhaps I was stumping myself with a simple typo or perhaps trying to call client.images without the proper references from another procedure.

What remains below are the few truths I know to be true and unusual about the client.images list.

  1. Images must be passed to the client.images variable one at a time.

    If I try to use the << operator to pass a list of images to the client, it handles it like a string and spams “/list” to the user’s screen.

    If I try to use the images.Add() operator to pass a list of images, nothing happens.  The image list is not added and there’s no explained reason why, it just doesn’t work.

    Fortunately, it’s not too hard to simply break down any list of images you have an add them one at a time to client images. That was ultimately the solution that ended a day of misery and woe for me.

  2. You cannot delete the client.images object.

    If you try, you get a “bad del” error.  This must be because the client (not the client object but the user’s actual client program) relies too much on the client.images variable to allow it to be cleared and reference to null.

    Instead, what you must do is delete each image from the client.images list manually.  If you want to clear out the whole thing, you can (contrary to my earlier beliefs) perform a simple loop like this:

    for (var/deleteThisImage in images)
    del deleteThisImage

    And it will work.  However, if you want to delete a specific image from that list of images, you need to be able to find it first, and that can be really hard to do if you have no reference variable to that image.  Thus, maintaining reference variables (or even lists of reference variables) is a good idea.

    The requirement to keep a reference to added images strikes me as an unfriendly feature for BYOND designers: Never should there be a point you’ve added something that impacts the user which you can’t take away. Still, I suppose I can appreciate the logic: if the BYOND game designer did their job right, and kept a reference to every image they’ve added, this should never happen in the first place. It may not be as user friendly, but it’s the more powerful implementation, and I can appreciate that.


Progress Check

Speaking of using BYOND Dream Maker, here we are, one week later, and I’m still working out the foundations of my extravagant game world.

That’s okay, I recall I read somewhere that Richard Garriott himself said that’s the best way to go about it: build what you want the engine to do first, then worry about the story/game (I forget which). Richard Garriott (a.k.a. Lord British) practically invented the tile-based engine, the first 8 Ultima games were presented in tile-based engines built from the ground up, so (like em’ or hate em’ for a certain clean slate’s WoW imitation) I think Garriott’s advice can be trusted on this matter!

Besides, I’m not really on day 7. Looking back to day 6, I created the system that handles all the moves done by the game pieces on a one turn per second system yesterday, and that was the closest thing I did to genuine progress. All days before that, I was mostly learning BYOND… am still learning BYOND judging by today’s entry. If I already knew how to program BYOND from the start as well as I do now, I’d probably be polishing a finished prototype by now. Rather than let that discourage me, I should chalk it up to a sign of how much I’ve learned since then.

By Design

While I have been busy learning BYOND lately, that’s no excuse to not have a design document. Design documents need little working knowledge of the BYOND engine or DM code, all the game designer really needs to know is that BYOND is a real-time, tile-based engine with implicit multiplayer support (so you should factor in there will be some network lag between moves that is, fortunately, handled automatically). It’s only after a design document is done that one need take off their designer hat and wear the coder hat. (Granted, each coder hat needs has a code design section, but you need to start knowing what you’re planning on doing.)

At this point in my own BYOND project, it’s clearer than ever that I need a target to shoot for. Because I’m lacking the kind of forethought a design doc exists for, my efforts to develop a game are very unfocused. For example, I created an action queue handler, yes. However, I haven’t thought through what kind of actions need to be handled, and so now I’m encountering a problem of what happens when a creature is interrupted and needs to stop moving and start defending itself.

I’m wearing the wrong hat to move this project forward: I really need to force myself to take a break from coding. As much as I apparently enjoy it given how easy the BYOND engine makes it to produce results, I’m at the point where I don’t know what result I’m trying to produce. It’s time to do some brainstorming and designing.

(Granted, if I was making a simple game, I could eyeball it. A simple overall design document could be easily generated in my head and that would work fine. However, after 25 years of gaming, I’m far from being a simple gamer at heart.)

2 Responses

  1. I’ve said this before (and will probably repeat it in later comments), but if I say anything you cover in later posts, I apologize. I’m moving chronologically through the posts and responding as I find reason to.

    First off, I don’t believe you need to keep a reference to the image object—client.images is itself a reference, so as long as you can distinguish among images you’re fine (or you can simply clear out all images and then re-add the ones you want, which isn’t very efficient). For example, consider the following (and I apologize if the following doesn’t render properly, I’m unfamiliar with wordpress formatting):

    client/verb/test()
    images += new/image
    images += new/image
    for(var/i in images)
    images -= i
    src << “Removing image \ref[i]”

    Also, keeping references around does not eat up considerable amounts of memory. Every variable reference is not an object, but rather simply a reference to an object, so consider the model:
    A is an object taking up 120 bytes of memory
    B is a reference to A, taking up 4 bytes of memory
    C is a reference to A, taking up 4 bytes of memory

    Of course, I naturally can’t say that the 4-bytes is a hard fact, but it should be relatively close. Since an image reference (B) would already exist in a client’s images list, A (the prime memory consumer) is already in memory, and keeping another reference (C) is not harmful.

    In response to which is more effective (delete or remove from the list), removing from the list would be more efficient. For some background on this, check out http://www.byond.com/members/DreamMakers?command=view_post&post=39699, particularly the Purging Cleanly section.

  2. Interesting! It appears I inadvertently lied when I said images was not a proper list.

    The thing is, the very first thing I tried was exactly as you said because it’s obviously the most implicit way to clear out an action queue. Something like:

    proc/ClearActionQueueImages()
    for (var/image/currentImage in images)
    images.Remove(currentImage)

    For some reason that broke – it didn’t work at all, it seemed to act as though it had no idea what the length of the client.images variable was and therefore a “for (var in list)” statement cannot function.

    However, I just tried it again … and it worked just fine!

    I don’t know what I did wrong the first time. Perhaps it was a simple typo on my part the first time that caused a false conclusion that client.images does not have better list support. Or maybe I was trying to call images from outside the client object without a proper reference. I’d say that better list functionality was added to images since I made this Blog post, but that’s probably is not the case.

    In any case, it seems client.images is a proper list after all. I’ll revise this blog entry accordingly. Thanks for catching that!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: