Building Your Game World
Anything that has a physical presence in the game world—a player, another character, a tool that players can use, a room, etc.—is called an entity. The two primary ways of creating entities are construct
and make
.
Entities can be of various types; for example, a Room
entity is a space that other entities can occupy, while an Item
entity is something that players can pick up and carry. In Ruby parlance, entity types are subclasses of the Gamefic::Entity
class. The Standard Library provides several useful types, including the aforementioned Room
and Item
. Authors can also make their own entity types by subclassing Gamefic::Entity
or another of its subclasses.
construct
The construct
method defines an attribute method that references an entity:
module Mygame
class Plot < Gamefic::Plot
# ...
construct :kitchen, Room, name: 'kitchen'
construct :plate, Item, name: 'plate', parent: kitchen
introduction do |actor|
actor.parent = kitchen # Put the actor in the kitchen
plate.parent = actor # Give the plate to the actor
end
end
end
make
The make
method is similar to construct
but does not create a corresponding instance method. These are sometimes called “anonymous” entities.
make Item, name: 'plate'
make Fixture, name: 'mirror'
make Supporter, name: 'table'
Authors can use make
to define entities at scripting time or create them dynamically during runtime. In the following example, the player can use the SPAWN command to create arbitrary items:
respond :spawn, plaintext do |actor, text|
item = make Item, name: text
actor.parent = item
actor.tell "You now have #{an item}."
end
Example gameplay:
> spawn magic wand
You now have a magic wand.
> spawn dog biscuit
You now have a dog biscuit.
construct
vs. make
There are a few important differences between construct
and make
that authors should consider when creating entities.
The construct
method is a class method. It’s only available when you’re defining your plot’s static rules.
module Mygame
class Plot < Gamefic::Plot
# ...
construct :home, Room, name: 'your home'
introduction do |actor|
actor.parent = home # This works because `home` was constructed at the class level
construct :yard, Room, name: 'yard' # This raises an error because the introduction gets executed at runtime,
# after the class-level scripts have already been executed
end
end
end
The make
method works at both the class and instance levels. At the class level, the entity will be created when the plot gets initialized. In blocks that get executed at the instance level—e.g., introduction
or respond
blocks—the entity will be created dynamically at runtime when the plot executes the block.
module Mygame
class Plot < Gamefic::Plot
# ...
# These entities are defined at the class level, so they get created when the plot gets initialized
construct :home, Room, name: 'your home' # The instance attribute is `home`
make Supporter, enterable: true, name: 'couch', parent: home # Note that `make` does not create an instance attribute
# The introduction block runs at the start of the game, after the plot's been initialized
introduction do |actor|
actor.parent = couch # Error: The `couch` attribute does not exist
actor.parent = pick!('couch') # OK: The `couch` attribute doesn't exist, but an entity named 'couch' does
construct :book, Item, name: 'book', parent: home # Error: You can't use `construct` while the game is running
make Item, name: 'book', parent: home # OK: The book will be created dynamically during the introduction
end
end
end
As a general rule, authors will usually want to create entities at the class level, e.g., the home and couch in the above example. Using construct
will give your script blocks (e.g., the code inside the introduction
) access to it via the specified attribute name (e.g., home
). Using make
will create an anonymous entity that doesn’t have a corresponding attribute method.
How do you decide whether to create an entity with an instance attribute via construct
or an anonymous entity via make
? It depends on whether or not you need to reference the entity elsewhere, such as making it another entity’s parent or using it as a required argument in an action. Example:
construct :home, Room, name: 'your home'
make Supporter, name: 'couch', enterable: true, parent: home
introduction do |actor|
actor.parent = home
end
# This response prepends a message to a LOOK HOME command before continuing to
# the next applicable response.
respond :look, home do |actor|
actor.tell 'You take a moment to admire your domicile...'
actor.proceed
end
Next: Scripting