Part 2 of this tutorial will teach you the basics of how to automate mouse inputs using RobotJS. We go over require statements, functions, how to sleep in JavaScript, while loops, variables, and how to use the mouse methods provided by RobotJS. By the end of this video we'll have a very simple stand-in-place RuneScape bot, and you'll have an understanding of JavaScript's fundamental concepts.
GitHub repo: https://github.com/learncodebygaming/woodcutter (view source code here)
Node.js: https://nodejs.org/
RobotJS: http://robotjs.io/
Visual Studio Code: https://code.visualstudio.com/download
Eloquent JavaScript: Free Online Edition / Paperback or Ebook Edition
W3Schools: https://www.w3schools.com/js/default.asp
In the first video, we installed Node.js and the RobotJS library. Now we're ready to start building our bot.
Right now your code should look like this:
// import the robotjs library
var robot = require("robotjs");
console.log('Starting...');
// move the mouse to the upper left corner of the screen
robot.moveMouse(0, 0);
console.log('Done.');
A require statement allows you to import code from another file or another package. Here we use it to import the RobotJS package so that we can use the functions inside of it. You can read more about how require statements work here: https://nodejs.org/en/knowledge/getting-started/what-is-require/
In VSCode, you can ctrl + click
on require("robotjs")
to open up the file that's being imported. In there, you can see all the available functions.
The universal print statement for JavaScript is console.log("");
. Anything you put inside those quotes will print to your terminal when your program runs.
On the robot
object, we are calling the mouseMove()
function, and we are providing to it two parameters (the x and y coordinates for the position where we want to move the mouse to).
The next thing I want to do is wrap our code inside a main function. We can declare a function like function main()
, where function is a keyword and main is the name we are giving the function. Because this function doesn't need any parameters, nothing appears inside the parentheses. This is followed by curly brackets, and the content of our function must be put entirely inside of these brackets. These brackets define the scope inside the function.
Once a function is defined, the code inside of it is not run until that function is called. At the bottom of our file is where we will call our main()
function.
// import the robotjs library
var robot = require("robotjs");
function main() {
console.log('Starting...');
// move the mouse to the upper left corner of the screen
robot.moveMouse(0, 0);
console.log('Done.');
}
main();
The reason we use functions is it encapsulates our logic inside a nice package that we can use and re-use later.
One of the things we know we're going to have to do with our bot is move the mouse, and then wait a little bit of time, and then move the mouse somewhere else. To do that, we need a way to pause the execution of our code while we're waiting to take the next action. This type of behavior is called a sleep function. Most programming languages have an easy built-in way to perform a sleep, but JavaScript does not. There are a few different ways to perform a sleep in JavaScript, but I find it easiest for our purposes to use this function:
function sleep(ms) {
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
}
To call this function, we would use sleep()
, like we did before with main()
, except this function expects us to pass in an argument for its one parameter. This parameter, labeled ms, is how many milliseconds we want to sleep for. So to wait for 2 seconds, we would call sleep(2000);
. Test this to confirm sleep is working by adding a sleep call in between the starting and done console.log
statements.
Now let's start up the game. It's going to be very important that we maintain a consistent window size and location when the game is running. That way pixel coordinates will be consistent while we're developing our code. I recommend you go to the graphics options in the game settings and use "resizable" mode, and then you can double click on the top bar of the game window to maximize the window size.
Inside RuneScape, you'll need to procure an "Iron hatchet" to begin woodcutting. Once you've done that, find some trees to chop down. I've been practicing on the trees just north of Lumbridge. You cut down trees just by clicking on them. So let's write some code to do that clicking for us.
Leave the initial sleep after the starting message is printed to give us time to switch to the game window after we start our code. Below that, we need to write code to move our mouse to a position on the screen where a tree is, and then we need to perform a click
function main() {
console.log("Starting...");
sleep(4000);
robot.moveMouse(1115, 483);
robot.mouseClick();
console.log('Done.');
}
To determine the x and y coordinates on your screen where a tree is, use the Print Screen button on your keyboard to take a screenshot while the game is open. You can then paste that into an image editor (Paint will work fine). You can then use that image editing program to determine the coordinates. I saw a tree at 1115, 483px, so those are the arguments I'm passing into the moveMouse()
function.
The x coordinate controls left and right, where 0 is all the way left, and the y coordinate controls up and down, where 0 is all the way up. Your maximum x and y values will depend on the resolution of your monitor.
Go ahead and test your code. It should perform a single click and then exit. You might find that your click misses the tree. In this case you can use the same method as before to find another coordinate position to click on.
Now we might want to click on that tree again after it respawns. To do this, we could add another pause after the mouse click, and after say 8 seconds we could call the mouse move and click again. And we could continue to copy and paste this section of code for as many times as we want this to happen.
But a better way to do this would be to use a loop. We can create a while loop by using the while
keyword, followed by parentheses and then curly brackets around the lines of code we want to repeat. Inside the parentheses, we need to put some condition to evaluate, so that as long as this condition is true the loop will continue, but when it becomes false the loop will stop.
We have the option of simply using true
as our condition, and this will create an infinite loop. To stop an infinite loop, you can go to your terminal and press ctrl + c
to kill your script.
function main() {
console.log("Starting...");
sleep(4000);
// basic infinite loop
while (true) {
robot.moveMouse(764, 557);
robot.mouseClick();
sleep(8000);
}
}
You can also run a while loop for a set number of times by using a variable that counts up to a certain number. This is called an iterator. Each time through the loop we increase the value of this variable by 1, until the while loop condition is no longer true. To run our loop 5 times, we could write code that looks like this:
function main() {
console.log("Starting...");
sleep(4000);
// loop 5 times
var i = 0;
while (i < 5) {
robot.moveMouse(764, 557);
robot.mouseClick();
sleep(8000);
i += 1;
}
}
So that's where we're going to pause. We've covered a lot here if you’re new to programming. The key concepts we've discussed are variables, functions (both declaring and calling), methods, and while loops. If you're still unclear on any of these topics, it'd be a good idea to spend a little bit of time reading more about them. See the links section at the top of this article for recommendations.
I know clicking over and over again in one spot isn't super useful or exciting, so in the next step we'll be chopping down multiple trees, we'll automate the process of dropping logs from your inventory, and we'll start doing some basic computer vision to find the next tree to chop by using the screen methods from RobotJS.