ModderDojo Topic 7: Planning and Building a Complex Structure Mod in Minecraft

PyrimidInside

This topic continues from ModderDojo Topic 6: JavaScript Operators and ScriptCraftJS Drone Functions.

Sharing a Server:

In previous weeks before we stopped for Christmas, some people struggled to make progress through no fault of their own: they were hampered by CanaryMod crashing a lot on some people’s computers.

To work around this, everyone can connect to my computer as the Minecraft server, and I will also create a shared folder on the computer so you can drop your mods into it.

Please review these notes from several weeks ago: Topic 2: Connecting to Each Other’s Servers.

This Week’s Challenge:

This week (and for the next week or two), your challenge is build a substantial mod in ScriptCraft that, when you run it, will create an impressive-looking structure!

A key step to success here is planning and design: as I have said before, a  programmer’s most important tools are paper and pencils, for figuring out what you want to create before you write code for it.

You should review the following:

 

Tunnel1

 

ModderDojo Athenry Topic 6: JavaScript Operators and ScriptCraftJS Drone Functions

Operators:

Operators in any programming language are used when you want to calculate something new: they operate on values. variables, or expressions to produce a new value.

Since ScriptCraft is built on the JavaScript langauge, it uses standard JavaScript operators. As it happens, many other programming languages (including C, C++ and Java) use the same operators or very similar ones.

JavaScript Operators

Drone Functions:

As we have seen before, in ScriptCraft you use a drone to do your building for you. The drone has functions that are part of it.

Here are some of the main drone functions that are useful when building your mods:

ScriptCraft Drone Functions

You can find lots more about these and other functions in the ScriptCraft API Reference: https://github.com/walterhiggins/ScriptCraft/blob/master/docs/API-Reference.md

Example: Build a Pyramid

This example is based on a very nice program writing by Ruaidhri from Coderdojo Athenry last year, updated slightly because some ScriptCraft commands have changed in the meantime.


// Copyright Ruaidhri from ModderDojo Athenry,
// slightly updated by Michael and Alex.
// Builds a pyramid with entrance and lights inside.

exports.pyramid = function()
{
echo('making a pyramid');
var d = new Drone(self); // 'self' means start drone beside me
d.up(1);

d.chkpt('begin');

var size=31;

// Make the walls
while (size > 0)
{
d.box0(blocks.sandstone,size,1,size);
d.right(1);
d.fwd(1);
d.up(1);
size=size-2;
}

// Entrance
d.move('begin');
d.right(15);
d.box(blocks.air,1,2,3);

// Lights inside
d.move('begin');
d.right(4);
d.fwd(4);
d.up(3);
d.turn(2);
var t = 0;
while (t<4)
{
d.hangtorch();
d.left(11);
d.hangtorch();
d.left(11);
d.turn(3);
t = t + 1;
}
d.move('begin');
}

ModderDojo Topic 5: Time to Get Constructive!

2013-12-07_12.25.59

This week builds on ModderDojo Topic 4, when we learned a bit about the basics of ScriptCraft and saw how it handles loops, decisions and variables compared to Scratch: https://cdathenry.wordpress.com/2015/11/11/modderdojo-topic-4-moving-from-scratch-to-javascript/

This week, our goal is to build a first structure mod in ScriptCraft. Ideally you should work in pairs. This to achieve this goal will involve:

During the session, I will ask people to load their mods onto my computer, demo them to the group, and explain how their code works. To get things started, at we can take a look at some mods from last year and how they work: https://cdathenry.wordpress.com/2013/11/10/modderdojo-athenry-our-scriptcraftjs-minecraft-mods/

Practical notes:

  • Read the ScriptCraftJS API reference to see what commands you can use for your structures: https://github.com/walterhiggins/ScriptCraft/blob/master/docs/YoungPersonsGuideToProgrammingMinecraft.md#building-stuff-in-minecraft
  • During development and testing, you can end up with lots of incomplete structures that slow down your CanaryMod server. A simple fix is to delete your world:
    • Stop your CanaryMod server
    • Open the CanaryMod folder on your computer: in it you will see a folder called worlds, and inside it one called default, and inside that default_NORMAL.  Delete default_NORMAL and all of its contents.
    • While you are at it, edit your world’s properties for when it is re-created: you can do this by opening canarymod – config – worlds – default – default_NORMAL.cfg. To make your new world superflat, write world-type=FLAT and you could also change other properties such as spawn-monsters=false
    • Restart CanaryMod to create a new, empty world
    • Re-run your scripts to recreate structures that you want

ModderDojo Topic 4: Moving from Scratch to JavaScript

GeneralFeaturesOfProgrammingLanguages

Note: some individual topics are short: we got most of the way through the first 3 in our taster session. See this post: https://cdathenry.wordpress.com/2015/09/27/minecraft-modding-taster-session-week-1/

JavaScript is a well-established programming language, mainly used in web development. ScriptCraft is a Minecraft mod that allows you to write JavaScript code for building structures in Minecraft and writing new Minecraft mods. (So it’s a mod for creating other mods.)

Steps 1-3: Install ScriptCraft, Learn how to Connect to a Server, and Create a First Mod

We covered these steps in the first two weeks:

  1. Getting Started with ScriptCraft and JavaScript
  2. How to Connect to Each Other’s Servers
  3. Creating our First ScriptCraft Mods

To try out ScriptCraft, look back at the introductory posts here: https://cdathenry.wordpress.com/2015/09/27/minecraft-modding-taster-session-week-1/

Step 4: Comparing JavaScript to Scratch

Some people criticise Scratch as being “childish”, but I don’t agree. While it is designed so that even 8 year olds can use it, it is still has all of the key features of ‘adult’ programming languages, as listed in the image at the top of this post.

(Technically, any programming language with variables, decision and loops is Turing Complete.)

This means that, if you already know how to write a Scratch programs that use these features, you will be able to apply that knowledge to any other language, such as JavaScript. The syntax of JavaScript is different, but it uses the same computational thinking.

Variables-Operators

Loops

Decisions

Notes:

  • Even though they have basic ideas in common, every programming language has its own specific commands that relate to its purpose: Scratch is focused on 2D games and animations, while ScriptCraft is focused on operating inside Minecraft, and JavaScript generally is used for interactive websites.
  • the echo command that features in these slides is not a standard JavaScript command, it is just used in ScriptCraft to display things on your screen in Minecraft.  Everything else is standard JavaScript.

Minecraft Modding Taster Session – Week 1

Slide1

This season at CoderDojo Athenry, the advanced groups are all starting with taster sessions of the various topics we will cover.

In Week 1, the topic we are covering is Minecraft Modding using JavaScript.

Here are the notes:

  1. Getting Started with ScriptCraft and JavaScript
  2. How to Connect to Each Other’s Servers
  3. Creating our First ScriptCraft Mods

Coming up next week: in introduction to Raspberry Pi and Electronics

ScriptCraft – An Exploding Chickens Mod

A few weeks ago we were lucky enough to have a visit from YouTuber and professional Minecraft modder (for the HyPixel server) codename_B (a.k.a. VladToBeHere, a.k.a. Ben).

Ben (left) addresses CoderDojo Athenry. ,Also pictured: Auburn, Ben's girlfriend, and our own Michael Madden

Ben (left) addresses CoderDojo Athenry. Also pictured: Auburn, Ben’s girlfriend, and our own Michael Madden

Ben is an extraordinary programmer who just breathes code. On his YouTube channel he regularly creates a complete MineCraft plugin in only sixty seconds!

After addressing the entire Dojo, Ben showed our modder group and a few other more advanced coders how to make a quick plugin which causes chickens to explode when a player kills them.

Ben’s mod was written in Java and used the Bukkit API to interface with MineCraft.

Porting the Plugin to ScriptCraft

ScriptCraft is built on top of Bukkit. Because of this, almost all the Bukkit API is available for use in ScriptCraft. I believe there are a few Java-only bits in Bukkit, but I haven’t encountered them.

I realized that, in theory at least, it should be possible to port Ben’s plugin to ScriptCraft. In practice, it proved to be more straightforward than I could have hoped. If you don’t already know Java, ScriptCraft is a great place to start if you want to create MineCraft mods.

ScriptCraft and Bukkit References

When writing something new, you’ll need to be able to look-up things that you are not familiar with. Two references I used for this script, apart from Ben’s original code, were:

  1. ScriptCraft API
  2. Bukkit API (from Spigot)

Browsing these resources is also a good way to see what can be done and to thereby generate new ideas.

Anatomy of the Plugin

The plugin is composed of four parts:

  1. Two variables to represent the Bukkit types which represent chickens and players respectively
  2. A loading function which we will run when the plugin loads
  3. An event handling function which will be called whenever one entity damages another
  4. A call to the loading function, at the bottom of the file, to make it run as soon as ScriptCraft reads it

Let’s talk about each of these parts in turn.

Variables to Represent Bukkit Types

After a require(‘events’) line (to make sure we can reference the events object), there are two lines as follows:

var bkPlayer = org.bukkit.entity.Player;
var bkChicken = org.bukkit.entity.Chicken;

These are ‘types’ which represent an entity of type Player and an entity of type Chicken respectively. We’ll use them in a bit to determine, when we’re told one entity has damaged another, that it was a Player entity causing damage to a Chicken entity.

The Loading Function

The next part of the script is the loading function. It’s short and really only does two things:

  1. Announces that the plugin has loaded by printing a message to the console
  2. Tells Bukkit that we’d like a function of our own to be run each time that a particular event occurs. In this case it’s the event that fires every time one entity damages another.

Here’s the code:

// The function which will run when we load this module
var _loadMod = function()
{
  // Announce ourselves to the console
  console.log("Exploding Chickens: [Loading ScriptCraft Mod]");

  // Tie our code into the event that fires every time one entity damages another
  events.entityDamageByEntity(_entityDamageByEntity);
}

We’re passing events.entityDamageByEntity() the name of our function we’d like to have run. That function (_entityDamageByEntity) and this function (_loadMod) both have underscores at the start of their names. It’s a JavaScript convention which indicates that we’re never be calling these functions by name from outside this file. They’re private or internal functions.

The Event Handling Function

This is the most complex part of the module, but not terribly so. Here’s the code:

// The code that we want to run each time one entity damages another
var _entityDamageByEntity = function(event)
{
  // Find out, from the event, who's getting damaged and who did the damage
  var damagedEntity = event.getEntity();
  var damagingEntity = event.getDamager();
  
  // If it's a chicken getting damaged by a player, game on...
  if (damagedEntity instanceof bkChicken && damagingEntity instanceof bkPlayer)
  {
    // Announce in the console that we've detected a player damaging a chicken
    console.log("Exploding Chickens: [A player damaged a chicken]");
    
    // Schedule a task to run in five seconds.
    server.scheduler.scheduleSyncDelayedTask(__plugin, function() 
    {
      // Check to see if the damage brings the chicken's health
      // down to, or below, zero. If so, it's dead...
      if (damagedEntity.getHealth() - event.getDamage() <= 0)
      {
        // Get the chicken's location
        var loc = damagedEntity.location;

        // Create an explosion at the chicken's location. 
        // A big one...
        loc.world.createExplosion(loc, 10.0);
      }
    }, 20 * 5);
  }
}

What does it do?

  1. Gets the entity that caused the damage and the entity that was damaged and check to see if they’re a player and a chicken respectively
  2. If they are a player and a chicken, Schedule a task to run in aprox. five seconds. This task can result in an explosion, so it’s nice to have a little “getting away” time.
  3. When our task runs, see if the amount of damage inflicted was enough to bring the chicken’s health down to zero (or below) and if it was, make a massive explosion where the chicken was.

The Bukkit function scheduler.scheduleSyncDelayedTask() needs a reference to the plugin which is asking for the task to be scheduled. In this case it’s ScriptCraft and there is a special automatic variable, __plugin, which ScriptCraft can use to refer to itself when it needs to.

And that’s pretty much it!

Getting it All Going

The last line in the file is just a call to our _loadMod() function. This will get run immediately by ScriptCraft when it read it, setting the mod into action:

// Run this script as soon as the file's loaded
_loadMod();

Finally

Here’s the mod in action:

Sorry chickens*.

The script file can be downloaded from here. I hope this inspires you to create your own server mods using ScriptCraft.

 

 

* The author is a vegetarian and general soft touch who even tends to feel bad about exploding virtual animals…

 

Automatically Generated ScriptCraft to Draw An Image

image_process

Having done tagger.js, I thought “wouldn’t it be nice not to have to specify the design by hand?”

I started thinking about how cool it would be to have a way to take an image file and use that to define the design that tagger.js was going to spray.

The first thing that I determined was that, as far as I can see, there isn’t any built-in support for the various image formats (GIF, JPEG, PNG, etc.) in ScriptCraft. OK, so what then? Well, web browsers are great at handling images in all kinds of different formats. The HTML5 canvas element is good for playing around with bitmaps and on top of all that, JavaScript is supported for the coding part!

So, with very little previous experience and plenty of Googling, I decided to make a web page which would allow the user to enter a file’s name, press a few buttons and a ScriptCraft script would appear, as if by magic. Development was pretty smooth, baring one significant road-bump which I’ll describe. I’m not going to go into details about how the HTML file was made, but it should be clear enough if you want to read it. I will however describe the process of colour mapping.

HTML5 and a Tale of Tainted Canvases

Say what? An odd problem I quickly hit was that I couldn’t just specify an image file from just anywhere (using HTTP:). In fact, even worse, when I directly loaded my HTML page in my browser (using FILE:), I couldn’t even load up an image file which was in the same directory as the HTML page.

More Googling followed. Turns out that the browser was trying to protect me from “cross-origin data”, which is a security risk. Luckily there was an easy solution. I downloaded a small web server application and used that to serve my HTML page, which eliminated the issue. The web-server I chose was Mongoose, because it’s a single application, light and fast, but you can use another web-server if you prefer.

Testing in Chrome

I used Google Chrome as my browser for developing and testing this webpage. Chrome has a JavaScript console, which greatly simplifies debugging scripts. It can be found from the menu to the right of the address bar, at More Tools > JavaScript Console. Among other features, It allows you to set breakpoints and watch the value of variables as the script executes. It will also show you errors in your code, where it finds them.

Colour Mapping

The most important part of this script is mapping the colour of each pixel in the original image to an equivalent block in MineCraft. For this example, I have restricted myself to the 16 wool colours. So, for every pixel in the original image, I have to choose the MineCraft wool block that’s the closest in colour.

MineCraft Wool Palette

MineCraft Wool Palette

The colours we are going to match against are above. If you’re curious, here’s how I generated this MineCraft palette, I laid all 16 MineCraft wool blocks in order, from white to black, and then took a screenshot. This screenshot was, of course, influenced by the lighting in MineCraft at the time I took the screenshot and each block had the wool texture applied to (i.e. they weren’t just one flat colour). I did some further image manipulation to improve the palette. I applied a strong blur effect to downplay the effect of the texture and then I used my image editors Histogram Stretch functionality to make sure that the whitest and blackest colours were pushed towards true white and true black. Finally I sampled one point on each block and that became my representative colour.

These colours, in RGB format, became an array in the JavaScript inside my webpage:

var paletteRGB = [[255, 255, 255], 
                  [222, 146, 79],
                  [177, 98, 186],
                  [115, 152, 197],
                  [178, 185, 60],
                  [76, 179, 67],
                  [213, 151, 159],
                  [51, 51, 51],
                  [164, 180, 170],
                  [44, 109, 122],
                  [116, 68, 167],
                  [30, 50, 113],
                  [59, 43, 14],
                  [35, 62, 15],
                  [132, 53, 40],
                  [0, 0, 0]];

RGB (Red/Green/Blue) is a common way to represent colour. Its three numerical values, each of which can range between 0 and 255, represent the relative strengths of the Red, Green and Blue channels. We can think of this as a co-ordinate system, with the R, G and B values as axes.

RGB Colour Space Imagined as a Cube

Description: RGB Colour Space Imagined as a Cube. Author: SharkD. Source: http://commons.wikimedia.org/wiki/File:RGB_color_solid_cube.png

The image above shows what this looks like. Pure white is on the corner nearest to us. The opposite corner, which we can’t see, is pure black. Colours aren’t just on the surface of this cube either, If we were to cut through it at any plane, we would see all the colours on the inside as well.

Therefore, the difference between two colours can be thought of as the distance between two points in RGB space. It’s Pythagoras’ Theorem again, as we saw in the rainbowk.js project, but in 3D. All we have to do is take the colour of each pixel in the input image, calculate how far is is from each MineCraft wool colour and pick the wool colour which is the closest in distance; that will be the most similar.

Easy right? Well, almost. Turns out, our eyes don’t quite work that way. We’re not as sensitive to changes in some colours as we are in others. We’re most sensitive to changes in shades of blue, and least sensitive to changes in shades of green. If asked to pick by eye, we might make a different choice for the “closest” colour than then one given by mathematics alone. Luckily, scientists have worked out factors which account for this. If you look in the final script you’ll see that there are factors which are used to weight (make more important) the difference in some colours than others. You don’t need to understand how these numbers were arrived at, just understand why they are there.

// It's Pythagoras' theorem again, but weighted.
function weightedDistanceSquaredRgb(r0, g0, b0, r1, g1, b1)
{
  // These weights are used to convert RGB -> YUV and are useful here
  // to enhance the perceived closeness of two colours
  var weightR = 0.299;
  var weightG = 0.587;
  var weightB = 0.114;
  
  // Distance between two points in space: sqrt(x^2 + y^2 + z^2)
  return distanceSquared(r0 * weightR, g0 * weightG, b0 * weightB,
                         r1 * weightR, g1 * weightG, b1 * weightB);
}

By the way, notice that we’re returning the distance squared here. It’s a common programming shortcut if we’re just checking for the nearest thing. If something has the closest distance, it will also have the smallest distance squared. Doing the square root calculation isn’t worth it – so we don’t.

Downloading and Running

The ZIP file containing this HTML file (image_process.html) and a few sample images can be downloaded from here. Remember, you’ll have to use a web-server to view this webpage and have it be able to process the images. Feel free to try your own images, just copy them into the same directory as the HTML file first, and remember to keep them small as every pixel becomes a MineCraft block. My sample images are all around 40px wide.

What’s Next?

Next week we’ll extend this little application to add optional transparency to the output and merge it with tagger.js so our image is sprayed onto the environment.

Scriptcraft – A Little Friendly Vandalism

For this week’s sample script, building on the ideas developed the week before, I decided to pander to the crowd a little and show a script called tagger.js which allows you to ‘spray’ a design, in a block type of your choice onto the environment. It can be downloaded from here.

Description: Graffiti near Moganshan Road in Shanghai. Photographer: Jakub Hałun. Artist: Unknown. Source: Wikimedia Commons

Defining Our Design

The script contains an array of strings used to defined our design. In the array each string represents a row. Each character in those strings represents a block. Spaces are treated as blanks, anything else is a part of our design. Take a look at this specification which represents a peace sign:

var tag = ["   ***   ",
           " ** * ** ",
           " *  *  * ",
           "*   *   *",
           "*  ***  *",
           "* * * * *",
           " *  *  * ",
           " ** * ** ",
           "   ***   "];

It may be a little hard to make out at first, because characters are much narrower than lines are tall and the whole thing is stretched. Comparing to this drawing should help:

Peace Sign

Peace sign design for tagger.js

I’ve used asterisks in my strings just because it fills the space, but any non-space character will work just as well.

Spraying Onto What’s Already There

The fun thing about tagger.js is that it places the design on whatever is already in the world. It’s not restricted to flat surfaces!

The script looks at the area the player is facing and moves forwards, within a sensible limit, until it encounters a solid block (not air). If it finds one, it changes the block to the requested type. These diagrams show the operation.

Tagger_before

Tagger_after

If no block is found within the search depth, as has happened several times in the diagram above, that part of the design is left out.

In Action

Below is a screenshot of tagger in action: a big stone sphere with a love heart, made of red wool, and a partial smiley, made of gold blocks, sprayed onto it (partial because I was too far away when I called the script and some blocks were beyond the default depth).

tagger

Not Only … But Also

The script also has a few other little interesting features. In common with many of the standard Scriptcraft functions, this one shows how to check for parameters being left out and how to provide default values when that happens. It also shows how to retrieve a part of an existing string, used here to get a single character at a time. Take a look at the script yourself to see how this happens.

Scriptcraft – Discovering the World

Introduction

Thus far, we have used Scriptcraft to build cool structures in our Minecraft worlds, but the interaction has been a little one-sided. We’ve placed objects into the world, but we’ve never stopped to ask: “What’s already there?”.

papapishu-Boys-running

That’s a powerful question to ask, because once we know what’s already in the world, our interaction with it becomes richer and opens up many new possibilities.

Objects in JavaScript

Objects in JavaScript have Properties and Methods. Properties are what they sound like; a value associated with object that we can get or set. Methods are actions, in the form of a function, that we can ask the object to perform.

If you thought of me as a Person object then you could imagine some of the Properties and Methods I might have. For Properties I might have things like NameAge, Height, Weight, etc. An example of a Method I might have could be SayHi() [notice the round brackets after the name marking this as a method]. That would make me say “Hi!”. A method might have arguments, so it could be SayHiTo(“Dave”) which would make me say “Hi Dave!”. A method could equally calculate a value. An example might be CalculateBMI() which would calculate my Body Mass Index (BMI) value based on my Height and Weight properties. On second thoughts… scratch that idea. SampleObject Exploring Existing Objects

How do we explore the objects in the ScriptCraft world? One way is to read the API documentation:

Another way is to look at the Scriptcraft code files themselves, especially drone.js.

Another handy, lazy, way to explore an object you already have a reference to in ScriptCraft is just to treat it like a string and pass it to self.sendMessage(). You’ll usually get a representation which shows some of the properties of the object and those properties’ values. It’s incomplete, but very quick and might show what you’re looking for.

Getting the Block Type

All of this was building to finding out, from Scriptcraft, what the block at a particular location is. Using a combination of the techniques listed above, I determined that I needed to call a method on the Bukkit World object called getBlockAt(). In Scriptcraft the server object has an array called worlds and the normal world is worlds[0]. For the curious; worlds[1] is the nether and worlds[2] is the end.

That’s everything we need to create a simple script to examine the block that we’re currently looking at. We can create a Drone, which is created at the block we are looking at by default, to get the location. Here is the main part of the code:

// Create a drone (will be placed at the block the player's looking at)
var d = new Drone();

// Gather information about the world, the drone's location
// and the block at the drone's location
var world = server.worlds[0];
var loc = d.getLocation();
var chunk = loc.chunk;
var block_info = world.getBlockAt(loc.x, loc.y, loc.z);

The remainder of the code is just printing this information to the console in a tidy way. We called it whats_that.js and it can be downloaded from here. The screenshot below shows it being run.

whats_that2

This will form the basis for some future projects.

Quick Final Note on Block Metadata

One final note and something that wasn’t discussed at our session last week: to fully define a block we need to know both its type and its metadata. Two wool blocks of different colours have the same type but different metadata values to distinguish them from one-and-other. Similarly steps use the metadata value to distinguish between the different possible orientations. You can use the whats_that() function to explore this.

Making a Rainbow in ScriptCraft – Part 2

rainbow

Welcome to Part 2 of “Making a Rainbow in ScriptCraft”. Take a look at Part 1 below if you haven’t already and them come back here. If you’re read Part 1, you can download the script by clicking here.

Approaches to Drawing the Rainbow

You might imagine that drawing a rainbow is just drawing a series of arcs, one inside the other. If you do that though, you’ll probably find that there are gaps between some of the arcs. Look at the diagram here:

arcs

The red circle fits perfectly inside the blue, but there are little gaps between the red and the green circles. Gaps won’t look brilliant in our rainbow so what can we do to avoid them?

What we can do is to scan across every single block that’s going to be in the rainbow and figure out what colour it should be based on how far it is from the centre. If we did that in the diagram above, the overall shape would be the same, but the little gaps would be red or green instead of empty. This is the approach our script takes.

If you’re interested, Walter Higgins uses a different technique in his built-in rainbow function. Run it and see: starting from the outside of the rainbow, he draws arcs a little thicker than he wants, and lets the ones inside them intersect a little bit. It’s more efficient (in terms of run speed) than my approach, but maybe not quite as flexible.

Array of Colours

At the top of the script, there is an array of colours. An array is a special type of variable that holds more than one value at a time.

// Colours for the rainbow
var colours = [blocks.wool.red, blocks.wool.orange, 
               blocks.wool.yellow, blocks.wool.lime, 
               blocks.wool.lightblue, blocks.wool.blue,
               blocks.wool.purple];

The first item in the array we can get with colours[0], the second with colours[1] and so on. Conveniently too, we can use colours.length in the code to know how many things are in the array without having to assume it’s always going to be seven. If you wanted to edit the script so it read:

// Colours for the rainbow
var colours = [blocks.iron, blocks.gold,
               blocks.diamond];

It would still work and give you a three bar rainbow made of iron, gold and diamonds. Cool? I think so. Hopefully this helps convince you of how convenient arrays can be.

Credit where it’s due: I borrowed the rainbow colours from Walter Higgins as he’d already gone to the trouble of figuring out which MineCraft colours were closest to the classical rainbow colours of red, orange, yellow, green, blue, indigo and violet. No point re-inventing the wheel! [Ok, I did come up with my own first and then discovered he’d done it better but whatever…]

Two Functions

The script contains two functions. The main function rainbowk and a second function called get_block. Why? The simple answer is, it’s a lot neater; easier to read and easier to understand. You never have to use more than one function, but if your code gets long and complicated you’ll eventually lose track of what is going on unless you break it up into simpler chunks.

The function rainbowk is the one we call from inside MineCraft and it’s the only one added to exports. It takes two arguments – the inner radius and the bar thickness. Inner radius decides how wide the inside of the rainbow is and bar thickness determines how wide each bar is. It scans over all blocks in the rainbow, one row at at time and from the ground up. At each block it calls get_block to figure out what block at that position should be.

The function get_block isn’t exported, so we couldn’t call it from inside MineCraft, but we can and do call it from inside rainbowk. It works out how far the block we are considering is from the centre of the rainbow, using the technique discussed in Part 1, and decides what the block type should be. The block type will either be one of those from the colors array if the location is inside the rainbow or blocks.air if outside the rainbow.

Mega-Rainbow

I showed the script to my nephew who attends CoderDojo Athenry in the Scratch Beginners group. He wanted to know what the “biggest” one he could make was. Well, there is no actual biggest but he decided to make a pretty huge one. He specified an inner radius of 50 blocks and a bar thickness of 12 blocks. For those wondering what the total width of that is, it’s this:

megarainbowdims

Two hundred and sixty eight blocks wide! It’s half as tall, so 134 blocks high. The total number of blocks inside the rainbow is 268 x 134 = 35912! It took about three quarters of an hour to build 🙂

megarainbow

Here it is utterly dominating a village! It was hard to get this much in the screenshot and keep a sense of scale 🙂

Thanks!

Thanks to everyone who’s read this post. Hopefully you’ll download the script and give it a try. I’ll be delighted to answer any questions on it at next Saturday’s session or indeed at any CoderDojo Athenry session in the new year.