Tuesday, June 2, 2009

Movement

I would say that, apart from "seeing", movement in a game or virtual world is the most important feature. While I can come up with a few games (Boggle) or worlds (chat room) that don't require the idea of player movement, they're the exception and not the rule. Given this, you would expect that movement would be a solid, ironed-out subsystem of virtual worlds in general, and Metaplace specifically.

Unfortunately, as recent discussion on the forums has shown, that's not quite the case. Sure, your starting world in Metaplace has a nice click-to pathfinding script attached, but that doesn't provide a solution for everyone.

Inputs

Not counting voice control or some telepathic USB device I don't know about, computers have two methods of user input: the keyboard and the mouse. Metaplace gives us access to both, for the most part, which means we have a choice on how we get instructions to our game world, and thus have a choice on how one might move around in our world.


The mouse

The mouse is probably the most common input method, since at a glance we can see our world, where we want to go, and can deftly move our mouse cursor there and simply click. Getting this click event is easy enough to do in Metaplace. But what about other mouse-based movement? In Ultima Online (you'll eventually get used to me using it as a reference) you did not "walk to" with the mouse, but rather "walked toward", by using the right-mouse-button on the screen and holding it down; the distance that the mouse cursor was from the player also let you decide between walking and running.

Unfortunately, this isn't possible in Metaplace, for two reasons: we don't have access to a right-click event (this brings up a Flash menu in the client; there are apparently hacks out there to allow right-clicking in Flash, but they aren't used for the Metaplace client); and we don't have access to mouse-up versus mouse-down events (and mouse-location), just mouse-clicked. This isn't a Flash limitation, from what I understand, but more a consideration of the bandwidth involved with sending the mouse location so-many times per second.

Still, we've got the click event, which lets us get our intentions across pretty well; we're also able to modify that with keys, such as ctrl-click to run there, or shift-click to sneak there.

The keyboard

The keyboard typically has two forms of movement: a "step-based" method and a "continuous-walk" method. There are also games where you control a cursor with the keyboard, but I suggest that that's only used when a mouse isn't available; and I suppose that you could have "direct" movement to waypoints using letters or numbers, but I'm going to happily ignore that idea for now.

In the step-based movement, players will press their arrow keys or WASD keys once for each "step" they wish to take; this would likely be in a tile-based game, where a discrete step is perhaps something visible in the world, and it represents the smallest unit of movement in the world. The continuous-walk movement instead listens for key-down events and key-up events, so holding down the arrow key will keep you walking in that direction until you release it (or until the game decides you can go no further, due to movement "points" running out, obstacles, or consumption by monsters.

The continuous-walk method is really just a shorthand way of doing the step-based movement, allowing the player to hold down the key to represent repetitive, consistently-spaced key presses. This means that continuous-walk also has the idea of a "step", but it's more likely that these steps are smaller: it's no big deal to quickly walk across a 64-"step" tile by holding down an arrow key, but you certainly wouldn't want to have to press the arrow 64 times for the same effect! The hold-and-release of a key allows the player to stop whenever they want, but there might also be the need to support the larger steps anyway, where releasing the arrow key still has the player continue to move until they reach the next full tile. It all comes down to the needs of the game world.

Movement

Once we know where we want to go (or at least, which direction we should start heading), how do we actually move? We could instantly appear there, we could slide across the screen in a direct line, or we could follow some sort of path around obstacles. Each of these methods has their place, depending on the world or game. Metaplace provides four ways to get you around.

MoveObject

The MoveObject() function is an instant teleport. No delay, no motion, just here one instant, and there the next. This might be used by simple board games, moving pieces around, though you may want the movement to be animated (if only for your opponent(s) to better see what your move was). It could be used in a simple RPG, stepping from tile to tile, but again, it might look better to have them slide along instead. Teleportation! There's one that surely needs to use MoveObject. The nice thing about MoveObject is that there's no issue of collision detection, because we're not moving through anything; however, it if there's something already at that location, MoveObject won't stop you from piling objects on top of each other, so if that's a problem, it needs to be handled in the code. MoveObject doesn't allow you to move to a blocking tile, however. And there's no issue about timing or animation, because it's an instantaneous event.

SlideObject

SlideObject gives that nice bit of animation to the game or world, allowing you to move your objects from here to there in a specified amount of time. Of course, you might still want to animate the sprite to make it look like it's walking, rolling or otherwise ambulating, but the movement there is nicely handled for you.

There are a few things to note: as far as the server is concerned, the object is instantaneously teleported. The client is told about the sliding, and does the job of moving the sprite along the right path at the right speed. However, the object's location along that path is always accessible, correctly, from the server. So what, then, does it mean that "as far as the server is concerned, the object is instantaneously teleported"? I believe this means that, for any subsequent requests by other objects, that location is considered occupied, such as if another object wanted to MoveObject there. I've admittedly not tested this out, yet, but that's the only meaning I can imagine.

Also, SlideObject will allow you to slide onto tiles that are blocking. This can be a good or bad thing. In the new Rocking the Metaverse world, the bouncers get you up to the VIP section by sliding you there, past all of the blocking tiles on the stairs. On the other hand, a movement system using SlideObject would have to look for blocking tiles manually to prevent the player from wandering over them. Also, SlideObject will allow the physics system (below) to trigger hit() and hit_by() events, if a collision takes place during the slide. If the blocking-tile behaviour of SlideObject is acceptable to you, this is a good way to go.

Physics

The Metaplace engine has a built-in physics system. Instead of specifying specific a location to move to or slide to, instead we can define a facing (direction) and a speed, and let our player keep going until we change these values. Physical objects are affected by quite a few things: they will fire the hit() and hit_by() Triggers when they hit objects, allowing you to decide what should happen; blocking tiles will fire a bounce_tile() Trigger, and also reverses your direction for you; and the world edges fire a bounce_border() Trigger, and again automatically applies the "bounce" off of it. There's also a facing() Trigger fired whenever the direction changes; this is useful for changing your sprite to rotate to another direction.

This automatic bounce effect can be a problem, though, if that's not the behaviour you want. It works well for a space maze game, like Uberspace, or an Arkanoid/Breakout game, but for other uses we might wish that movement in the direction of the blocking object was dampened down to zero, just stopping movement in that direction. Of course, that's what you can do with the bounce_tile() and bounce_border() Triggers, but I would almost expect the two methods of handling it to be swapped -- the bounce to be coded, and the stopping to be standard. Or perhaps a flag?

Alas, these aren't the only concerns with the physics system. Objects tend to "drift", where the client's representation isn't quite the same as the server's, which can lead to inexplicable collisions (the server sees the collision, but the player's view in the client doesn't match or make sense) and to sudden lurching movements (when the player changes the direction or speed, and the server suddenly updates the client with some out-of-sync location information). Additionally, detecting collisions between blocking tiles or the corners of the world boundary don't quite work, allowing objects to escape into the unknown.

Still, if you have good control over your physical objects, and use the physics system for short, immediate movements, it can provide more flexibility than SlideObject. The fine-tune control over direction, speed and even acceleration might be easier to do with physics than it is using SlideObject, where you might have to convert angles and slide times or perform multiple slides to get a nice effect.

pathfinding

The pathfinding system is what you get with most of the worlds that you create in Metaplace, generally tied to the mouse click. This system uses an algorithm called A* (a-star) to try to find the best path from where you are now to where you want to go, avoiding blocking tiles and tiles with blocking objects on them.

Whether or not a path is found, a Trigger is fired, either path_begin() or path_not_found(), so you can either start animating your walk, or give a loud BZZZ if the player cannot get somewhere. Upon reaching the end, a path_end() Trigger is also fired, to allow the walk animation to be turned off, or to allow some NPC to pathfind to its next location (perhaps because it's walking a circuit, patrolling).

The pathfinding system uses the physics system, which means that on the way, you can receive hit() and hit_by() Triggers, as well as get facing() calls. In theory, you shouldn't receive any bounce_border() or bounce_tile() Triggers, since the path has walked around those for you. Finally, you can also specify a "mode", which tells the pathfinding system that it can or cannot walk across diagonals; this is useful if you want to avoid the appearance of a collision when there isn't really one (a future post) -- you can see some good diagrams on the PathToLocation() wiki page.

The best solution?

From the four, it sounds like the pathfinding is the best way to go for most uses, especially if you need to avoid blocking tiles, if you care about collisions, and if you want the player to be able to single-click their way around. It can also be tied to an key-press movement system, where with each press, the system attempts to pathfind one tile left/right/up/down. A key-holding continuous system is a little trickier; based on the speed at which the pathfinding gets the player from tile to tile, you could have your movement code continuously calling the pathfinding system again, from within path_end(), if the key is still being held down. This would mean that the animation should not be stopped, if it exists, which might cause some collisions between multiple modules trying to handle the path_end() Trigger. Attention would have to be paid to the smoothness of the motion, to see if multiple pathfind calls, chained together like this, would appear as a jerky, stop-and-start motion.

Pathfinding, because of its adherence to blocking objects, isn't useful in worlds where you can ignore these features, such as when you can fly over terrain. As mentioned before, the bouncer in the Rocking the Metaverse world has to SlideObject you into the VIP room, because pathfinding will NOT get you there (as you can see for yourself if you click up top). And, if you're looking for the instant-move effect, pathfinding might be able to fake it with a high enough speed, perhaps... I haven't tried!

I think the marketplace needs a handful of movement systems available, so those who know what they want can piece it together. Whether it's mouse-clicks, key-presses or key-holds, and moving, sliding or physics, there's no reason we can mix-and-match these together, or even have a single module that allows the world administrator to select their world's manner of movement. Unfortunately, over the span of the alpha and beta testing, there have been a variety of keyboard and mouse movement systems, using move, slide, physics and pathfinding, each at one point being the "standard" movement script provided with your new world. It would a shame if the click/pathfinding system being used by the avatars, quite obviously the most popular method now, becomes the only way people know how to interact with their worlds.

No comments:

Post a Comment