The Brain type allows you to program behavior of yourself, explorers you open in anonymous windows, or others who attach the Brain.
To get started, just login, hit Create, select Brain, draw something, name the creation, and hit the Save button. Leaving the text field empty means you've created an empty Brain, which can be overloaded dynamically when putting it on, ideal during development. Now go to an area where you're editor, place the Brain, and walk over it and hit Space to put it on. A code editor opens. A bit of sample code should be preloaded.
Tip: Others can't bring their own Brains into your area if they're not an editor, but you can place an empty Brain there (or one with the attribute "offers editing") to give them a chance to dynamically overload it.
Tip: If you're looking for a good font, try our Doid.ttf, which is a spin on Droid especially suited for programming. After saving locally and installing as font on your machine, you can adjust your browser settings to use this as default monospace font.
What Brain code looks like
To program Brains, you need to know some JavaScript (there's many great resources available). Here's a sample code structure:
// An example script var chanceForMovement = 25; function update(my) { var reaction = { left: false, right: false, up: false, down: false}; if ( chance(chanceForMovement) ) { reaction.left = true; } return reaction; }
The default update routine is called 15 times a second and needs to be present in every script. It receives a my parameter which contains a variety of information you're receiving: what the world around you looks like, what other people or items are there, what you're currently touching and more.
Using this input, you can then determine what to do and return it as part of a reaction structure.
In above script, we're defining a Brain-global variable called chanceForMovement, set to 25. We're also using the native chance function. Whenever the given chance of 25% is true, we're setting the reaction to move left. We're finally returning the reaction. When we hit the Start button on this script, we can see ourself moving a bit left randomly. Try setting the chanceForMovement value to something higher, like 75, and you find the movement changes when you hit Stop and Start again.
Once you're happy with a script, you can copy it from the editor, create a new type Brain, hit the text button at the top, and paste the code into it. This Brain is now shareable with others by placing it in the world (its code contents can then be peeked at from the item context menu, but the brain cannot be directly overloaded). You can also click it from your panel to use it. While a Brain is attached, everyone sees a little dot in the place of your name.
The My object with example values
-
sight
- placements[x][y] // grid of size my.sight.scope in each direction
- type enumType value // e.g. enumType.solid
- id "50372a99f5d33dc56f000001" // persistent and unique
- name "red brick"
- attributes {hovering: true, fast: true, ...} // an object with optional properties
- rotation 90 // missing, or 90, 180, 360
- x 10 // the horizontal center position
- y 10 // the vertical center position
- isFlipped undefined // missing, or true if direction horizontally flipped
- isSolid true // missing, or true for e.g. type solid, flexible...
- isHarmful undefined // missing, or true for e.g. type deadly, or has harmful attributes
- isGathered undefined // missing, or true if it's type Gatherable and gathered
- entities[]
- type enumType value // enumType.being, ...emission, or ...item
- id "50372a99f5d33dc56f000001" // persistent and unique (person ids are anonymized)
- fromId "abcdefg123" // only for emission or item, the id of the person who emitted or threw it
- name "[abcdefg123]" // a name placeholder you can use, it will convert back to the actual name
- attributes {hovering: true, fast: true, ...} // an object with optional properties
- direction -1 // -1 (left-facing default) or 1 (right-facing)
- x 10 // the horizontal center position
- y 10 // the vertical center position
- width 15
- height 16
- isMe false // whether or not this is us
- velocity {x: 0, y: 0}
- for beings:
- body undefined // missing or data
- [see body data]
- wearable undefined // missing or data
- [see body data]
- mountable undefined // missing or data
- [see body data]
- holdable undefined // missing or data
- [see body data]
- brain undefined // missing or data
- [see body data]
- acts undefined // or true, if person hits action, e.g. uses an equipment
- does undefined // or name of a motion one does
- stance enumStance.sitting // missing, or enumStance.swimming, climbing, creating, sitting, lying
- scope 10 // the distance in blocks one sees in each direction
- placements[x][y] // grid of size my.sight.scope in each direction
-
touch
- left null // null or placement object (see above)
- right null // null or placement object (see above)
- top null // null or placement object (see above)
- bottom null // null or placement object (see above)
- center null // null or placement object (see above)
- topLeft null // null or placement object (see above)
- topRight null // null or placement object (see above)
- bottomLeft null // null or placement object (see above)
- bottomRight null // null or placement object (see above)
- forward null // point takes direction into account
- bottomForward null // point takes direction into account
- topForward null // point takes direction into account
-
hearing[]
- content "hello there"
- type enumType value // enumType.speech or enumType.sound
- fromId "abcdefg123" // undefined or for speech, a person's id. Persistent for session only
-
body undefined // missing or data
- type enumType value // e.g. enumType.body
- id "abcdefg123" // for body, the id persists for the session only
- name "" // name, or empty for body
- attributes {hovering: true, fast: true, ...} // an object with optional properties
-
wearable undefined // missing or data
- [see body data]
-
holdable undefined // missing or data, see body above
- [see body data]
-
mountable undefined // missing or data, see body above
- [see body data]
-
brain undefined // missing or data, see body above
- [see body data]
- energy 100 // 0 (dead) to 100
- x 10 // the horizontal center position
- y 10 // the vertical center position
- width 15
- height 16
- velocity {x: 0, y: 0}
- direction -1 // -1 (left-facing default) or 1 (right-facing)
-
status
- isLoggedIn true
- isEditorHere false
-
control
- left true // whether or not it's currently manually pressed
- up false // whether or not it's currently manually pressed
- right false // whether or not it's currently manually pressed
- down false // only available if brains are non-removable
- action false // whether or not it's currently manually pressed
- leftOnce false // whether or not left was pressed once
- upOnce false // whether or not up was pressed once
- rightOnce false // whether or not right was pressed once
- (please note down is used for unequipping a brain, so unavailable here)
- actionOnce false // whether or not action was pressed once
- name "[abcdefg123]" // a name placeholder you can use, it will convert back to the actual name
- id "50372a99f5d33dc56f000001" // persistent and unique
The Reaction object with example values
Here's a full list of values you can set in the reaction object (all properties are optional to pass):
- left true // same as holding the left arrow down until the next update
- up false // same as holding the up arrow down until the next update
- right false // same as holding the right arrow down until the next update
- down false // same as holding the down arrow down until the next update
- action false // same as holding down space/ action button until the next update
- leftOnce true // same as pressing & then releasing the left arrow
- upOnce false // same as pressing & then releasing the up arrow
- rightOnce false // same as pressing & then releasing the right arrow
- downOnce false // same as pressing & then releasing the down arrow
- actionOnce false // same as pressing & then releasing space/ action button
- speech "hello" // up to 20 characters and once per 1.5 seconds
- motion "waves" // up to 20 characters and once per 1.5 seconds
- playInstrument "d#2" // plays this note on the held instrument. Can also be an array, and values can also be numbers if it's a drum kit. The octave is optional, e.g. "d" works too.
- unequip true // unequips the brain (this happens before other remaining reactions are then performed)
Logging
You can use the following functions to log debug information when the script editor is opened (you can pass as many parameters as you like):
log('my status', my.status); logOnce(my.velocity.x); // only logs once per run logFresh(1 + 1); // clears the log and logs something new logFresh(); // clears the log
Types
To check a placement's type, you can use (where someBlock is e.g. my.touch.forward):
if (someBlock.type == enumType.thingInFront) { ... }
The enumType integer value is persistent and won't ever change.
If you are only interested in whether or not a type is solid, or harmful, you can use these groups instead:
if (someBlock.isSolid) { ... } if (someBlock.isHarmful) { ... }
Here are all type names (you can check for them using e.g. enumType.back):
Allowing any brain-equipped person to affect others
By default, only people in one's friend list can affect someone with e.g. a harmful emitter. If you want to create brain-equipped enemies in an area, you can allow them to affect others by including the following in e.g. an area-global interacting:
Someone Arrives: /they can be affected by brain-equippers
Here's some more rights you can set.
Sound
You can add a sound to Brains.
Limits
You may use up to 3 brain-equipped sessions at once.
Fullscreen
Note you can enter fullscreen mode at any time, also when the Brain editor is opened, by pressing F11.
Native functions
The following functions are available in addition to JavaScript's native functions:
// True or false, depending on a chance of 0 - 100% chance(percent); // Returns a random integer from minInt to maxInt. // The value is deterministic for Happenings and Generators so // that everyone sees the same (same for Math.random()). getRandomInt(minInt, maxInt); // For use with the Changer, // converts pixels from palette indexes to rgba: convertToFullColor(creation); // Returns a copy of the object so that // changes won't affect the original: cloneObject(object); // Limits a value into the numbers, // sets to minimum if not numeric: toLimit(value, min, max);
Examples
Example: Sight
Here, we are converting what we see around us as we move into log output letter art:
function update(my) { var reaction = {}; showMap(my.sight.placements, my.sight.scope); return reaction; } function showMap(placements, scope) { var s = ''; var scopeY = Math.round(scope / 3); for (var y = -scopeY; y <= scopeY; y++) { for (var x = -scope; x <= scope; x++) { if (x == 0 && y == 0) { s += '▣'; } else { var block = placements[x + scope][y + scope]; s += block && block.isSolid ? '■' : '□'; } } s += "\n"; } logFresh(s); }
Example: Touch
In this example, we're moving left or right. When there's a solid or harmful obstacle we change direction by going left or right. If there's a gap in the ground we're jumping. Randomly in-between we're hitting the action button (if we're holding an equipment), so if say we have a hammer equipped, it would swing every now and then. We're also printing something to the log when that happens. On the side, we're looking for a coin item to pick up (we check for the occurrence of the string "coin" in the item's name; note all item names are lower-case).
var reaction = {}; var foundCoinTimer = null; function update(my) { reaction = {}; var direction = my.direction; if ( my.touch.forward && (my.touch.forward.isSolid || my.touch.forward.isHarmful) ) { direction *= -1; } if (!my.touch.bottomForward || !my.touch.bottomForward.isSolid) { reaction.up = true; } if ( my.holdable && my.holdable.type == enumType.equipment && chance(5) ) { reaction.actionOnce = true; log('Action time!'); } if (direction == -1) { reaction.left = true; } else { reaction.right = true; } handleCoinFinding(my); return reaction; } function handleCoinFinding(my) { if (!my.holdable) { if (!foundCoinTimer) { if ( !my.holdable && my.touch.center && my.touch.center.type == enumType.item && my.touch.center.name.indexOf('coin') >= 0 ) { foundCoinTimer = new Timer(); reaction.speech = 'i found a coin!'; stopMoving(); } } else { reaction.left = false; reaction.right = false; if ( foundCoinTimer.seconds() >= 1 ) { reaction.actionOnce = true; foundCoinTimer = null; stopMoving(); } } } } function stopMoving() { reaction.left = false; reaction.right = false; reaction.up = false; } function Timer() { this.timeAtStart = Date.now(); this.seconds = function() { return ( Date.now() - this.timeAtStart ) / 1000; } this.reset = function() { this.timeAtStart = Date.now(); } }
Example: Hearing
This time, we react to when others say "jump", "left" or "right". There are different ways to go about this, e.g. you could create a function that accepts a list like {jump: 'up', ...} and applies reaction[mappingFound] = true, and instead of a for-loop there may be a my.hearing.forEach() and so on. Note in below we don't check for the hearing.type "speech", so this may later also react to a sound effect named e.g. "jump".
function update(my) { var reaction = {}; for (var i = 0; i < my.hearing.length; i++) { var hearing = my.hearing[i]; var isMe = hearing.fromId == my.id; if (!isMe) { switch (hearing.content) { case 'jump': reaction.up = true; break; case 'left': reaction.left = true; break; case 'right': reaction.right = true; break; } } } return reaction; }
Example: Looking for gold
Here we try to find gold!
var memory = {didFindGold: false}; function update(my) { var reaction = {}; if (!memory.didFindGold) { lookForGold(my, reaction); } return reaction; } function lookForGold(my, reaction) { var touchType = my.touch.center ? my.touch.center.type : ''; var touchName = my.touch.center ? my.touch.center.name : ''; if (touchType == 'climbable') { reaction.up = true; } else if ( touchName.indexOf('gold') >= 0 ) { reaction.speech = 'i found gold!'; memory.didFindGold = true; } else { moveLeftAndRightAndAvoidGaps(my, reaction); } } function moveLeftAndRightAndAvoidGaps(my, reaction) { var direction = my.direction; if ( my.touch.forward && (my.touch.forward.isSolid || my.touch.forward.isHarmful) ) { direction *= -1; } reaction.up = !my.touch.bottomForward || !my.touch.bottomForward.isSolid; if (direction == -1) { reaction.left = true; } else { reaction.right = true; } }
More...
Also check out the main introductory help and the Interacting help. Got a question which isn't answered here, or new ideas and feedback? Have a look here please.