jonleung / WoofJS

JavaScript Unleashed

Home Page:http://woofjs.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

WoofJS - JavaScript Unleashed

WoofJS is a JavaScript framework for creating games by The Coding Space.

If you're new to JavaScript, you may want to get acquainted with its basic syntax and paradigm.

Getting Started

We reccomend you File>Clone this JSBin to get started: https://jsbin.com/lekovu/edit?js,output

Alternatively, you can put Woof between your HTML <head> tags.

<script src="https://cdn.rawgit.com/stevekrouse/WoofJS/14cf402c5c2738431532a8ae752c94fbc96fa0b1/woof.js"></script>
var circle = new Circle({})
forever(() => {
  circle.radius = circle.distanceTo(mouseX, mouseY)
})
circle.onMouseDown(() => {
  circle.color = randomColor()
})

Creating Sprites

To create a new sprite, start by typing one of the following lines:

var IMAGE_NAME = new Image({});
var TEXT_NAME = new Text({});
var CIRCLE_NAME = new Circle({});
var RECTANGLE_NAME = new Rectangle({});
var LINE_NAME = new Line({});

Pro tip: Be sure to change the SPRITE_NAME to a name of your choice!

Sprite Options

You may add any of the following options to any of your sprites:

var IMAGE_NAME = new Image({x: 100, y: 20, angle: UP, rotationStyle: "ROTATE", showing: true});
var TEXT_NAME = new Text({x: 50, y: -100, angle: DOWN, rotationStyle: "NO ROTATE", showing: true});
var CIRCLE_NAME = new Circle({x: 0, y: 0, angle: 90, rotationStyle: "ROTATE LEFT RIGHT", showing: false});
var RECTANGLE_NAME = new Rectangle({x: 62, y: 12, angle: 0, rotationStyle: "ROTATE", showing: false});
var LINE_NAME = new Rectangle({x: maxX, y: maxY, angle: 0, rotationStyle: "ROTATE", showing: false});

Specific Options

Each sprite has its own specific options. For example, Image has url, Circle has radius, and text has fontFamily:

var IMAGE_NAME = new Image({url: "https://i.imgur.com/SMJjVCL.png/?1",width: 30, height: 30});
var TEXT_NAME = new Text({text: "Hello world!", size: 12, color: "rgb(100, 50, 240)", fontFamily: "arial", textAlign: "left"});
var CIRCLE_NAME = new Circle({radius: 10, color: "#ffffff"});
var RECTANGLE_NAME = new Rectangle({width: 20, height: 55, color: "pink"});
var LINE_NAME = new Line({x: -100, y: 100, x1: 10, y1: 20, color: "pink", lineWidth: 10});

Motion

move 10 steps NAME.move(10);

turn right NAME.turnRight(15);

turn left NAME.turnLeft(15);


point in direction

NAME.angle = LEFT;
NAME.angle = RIGHT;
NAME.angle = UP;
NAME.angle = DOWN;
NAME.angle = 47.7;

point towards mouse NAME.pointTowards(mouseX, mouseY);

point towards (sprite) NAME.pointTowards(NAME.x, NAME.Y);


go to x, y NAME.x = ...; NAME.y = ...;

go to mouse pointer NAME.x = mouseX; NAME.y = mouseY;

go to sprite NAME.x = otherNAME.x; NAME.y = otherNAME.y;


change x by NAME.x += ...;

change y by NAME.y += ...;

set x to NAME.x = ...;

set y to NAME.y = ...;


set rotation left-right NAME.setRotationStyle(“ROTATE LEFT RIGHT”)

all around NAME.setRotationStyle(“ROTATE”)

don't rotate NAME.setRotationStyle(“NO ROTATE”)

LOOKS

show NAME.showing = true;

hide NAME.showing = false;


change image IMAGE_NAME.setImageURL('...')

You can only setImageURL() for Images.

Change the color for rectangles, text, lines and circles:

RECTANGLE_NAME.color = "purple";
TEXT_NAME.color = "rgb(10, 150, 30)";
LINE_NAME.color = "#ff20ff";
CIRCLE_NAME.color = "green";

set size

You set the size in different ways for each type of sprite:

IMAGE_NAME.height = ...; IMAGE_NAME.width = ...;

RECTANGLE_NAME.height = ...; RECTANGLE_NAME.width = ...;

CIRCLE_NAME.radius = ...;

LINE_NAME.x1 = ...;
LINE_NAME.y1 = ...;
LINE_NAME.lineWidth = ...;

TEXT_NAME.size = 20;

send to back layer NAME.sendToBack();

go to front layer NAME.sendToFront();


change image

Set the backdrop to an image URL:

setBackdropURL("http://example.com/img.jpg");

Set the backdrop to a color:

setBackdropColor("blue");

Set the backdrop size:

fullScreen = false;
var width = 300;
var height = 400;
setBackdropSize(width, height);

PEN

clear clearPen();

pen down NAME.penDown = true;

pen up NAME.penDown = false;

set pen color NAME.penColor = “blue”;

set pen color NAME.penColor = “#ff20ff”;

set pen color NAME.penColor = “rgb(10, 100, 20)”;

set pen size NAME.penWidth = 4;

DATA

making a variable var sampleVariable;

setting variable to value sampleVariable = ...;

You can combine creating/naming a variable with setting it:

var sampleVariable = ...;

changing variable sampleVariable += ...

showing a variable new Text({text: () => "variableName: " + variableName});

("Showing a variable" works by giving a Text Sprite a function instead of a "string in quotes" as its text attribute. The Text Sprite constantly reevaluates the function which keeps the value on the screen in sync with the value of the variable.)


making an array var sampleArray = [];

adding thing to array sampleArray.push(...);

(You can add anything to an array in JavaScript, including numbers, strings, but even Sprites, functions, and other arrays.)

length sampleArray.length

sampleArray[1]

removing things from array sampleArray.splice(startIndex, endIndex);

checking if thing is in array sampleArray.includes('...');

show array new Text({text: () => "listName: " + listName});

Do something for each thing in an array:

sampleArray.forEach(thing => {
  console.log(thing)
});

Check if a condition holds for at least one thing in an array:

if (sampleArray.some(thing => thing.over(mouseX, mouseY))) {
  ...
}

Check if a condition holds for everything in an array:

if(sampleArray.every(thing => thing.touching(...))) {
  ...
}

Find something in an array:

var needle = sampleArray.find(thing => thing.touching(...));
if(needle) {
  console.log(needle);
}

Events

Warning: The shape of events in Scratch prevent you from putting an event inside other blocks. Although JavaScript doesn't prevent you from putting events inside other blocks, you should avoid it. For example, don't place an onMouseDown event inside a forever block.

on flag click

ready(() => {
  ...
});

Note: Unlike in Scratch, using ready() is reccomended but not always required.


onclick

onMouseDown(() => {
  ...
});

On mouse up:

onMouseUp(() => {
  ...
});

onclick

NAME.onMouseDown(() => {
  ...
});

On mouse up:

NAME.onMouseUp(() => {
  ...
});

If pressing ...

onKeyDown(() => {
  ...
});

If pressing ...

onKeyDown(key => {
 if (key == 'A') {
   ...
 }
});

onKeyDown(key => {
 if (key == 'UP') {
   ...
 }
});

Sensing

touching mouse NAME.mouseOver()

touching edge

If you want to see if the center of your sprite is outside of a boundary, here are some expressions that could be helpful:

NAME.x > maxX
NAME.x < minX
NAME.y > maxY
NAME.y < minY

touching NAME NAME.touching(OTHER_NAME)

NOTE: touching detects the rectangular boundary of a sprite, so if you have an image with a large transparent border, you will need to trim your image to make touching accurate.


distance to mouse pointer NAME.distanceTo(mouseX, mouseY);

distance to other thing NAME.distanceTo(OTHER_NAME);


If pressing ... keysDown.includes('SPACE');

List of keys currently pressed: keysDown


mouse x mouseX

mouse y mouseY


x position of... NAME.x

y position of... NAME.y


Previous mouse X: pMouseX

Previous mouse Y: pMouseY


Mouse X speed: mouseXSpeed

Mouse Y speed: mouseYSpeed


Right edge of the screen: maxX

Left edge of the screen: minX

Top edge of the screen: maxY

Bottom edge of the screen: minY


Width of the screen: width

Height of the screen: height


hour();

Hour in military time: hourMilitary();

minute();

second();

dayOfMonth();

dayOfWeek();

month();

year();

OPERATORS

... + ...

... - ...

... * ...

... / ...


pick random number random(..., ...);

Random X value on the screen between minX and maxX: randomX()

Random Y value on the screen between minY and maxY: randomY()

Random color: randomColor()


... < ...

... > ...

... == ...

Less Than or Equal To: ... <= ...

Greater Than or Equal To: ... >= ...

Not Equals: ... != ...

Between Two Numbers : NAME.x.between(minX, maxX)


and ... && ...

or ... || ...

not !(...)


"hello" + "world"

"world".substring(0,1)

"world.length


... % ...

Math.round(...)

More Blocks

Make Block

You can create a function with a name:

var namedFunction = (input1, input2) => {
  // do stuff here with input1 and input2
}

You can run a function by putting parentheses next to its name:

namedFunction(1, 2)

You need to do this even if the function takes no parameters:

namedFunctionWithoutParameters()

But you can also create a function without a name, which is called an anonymous function:

forever(() => {
  sprite.x++;
})

Control

wait

There is no wait block in JavaScript. Instead, you can use after():

after(..., "seconds", () => {...});

However, after() is a poor substitute for Scratch's wait block and you may find some programs very difficult to write without wait. Please accept my apologies on behalf of the designers of JavaScript.

If you want to wait at regular intervals, use every():

every(..., "seconds", () => {
  ...
});

repeat

repeat(10, () => {
  ...
});

forever

forever (() => {
  ...
});

if... then...

if (...) {
  ...
}

if.. then... else...

if (...) {
  ...
} else {
  ...
}

repeatUntil(() => ..., () => {
  ...
});

There is no wait-until in JavaScript. You can simulate a wait-until block by specifying a third function to a repeatUntil. Refer to the "Control Flow" section below for more details.

repeatUntil(() => ..., () => {}, () => {
  ...
});

when() is a short-hand for a forever-if statement.

when(() => ..., () => {
  ...
});

stop(all) freeze();

Reverse freeze or stop all: defrost();

cloning

// create a list to store all of the clones
var clones = [];
every(4, "seconds", () => {
  // create a clone every 4 seconds
  var clone = addCircle ({radius: 10, color: "pink", x:
randomX(), y: randomY()});
  // add each clone to the list
  clones.push(clone);
});

forever(() => {
  // forever, for each clone in clones
  clones.forEach(clone => {
    // move it to the right
    clone.x++;
    // delete it if it goes off the screen
    if (clone.x > maxX) {
      clone.delete();
    }
  })
});

Delete an object: NAME.delete();

Only allow something to happen once every X miliseconds:

onMouseDown(throttle(() => score++, 1000)) // after a mousedown, you won't be able to trigger this event again for 1000 milliseconds 

Control Flow

There are two types of commands in JavaScript:

  1. Synchronous: "Do this immediately and move on when it's done."

Synchronous example in real life: Open heart surgery. When a doctor begins open heart surgery on a patient, she stays in the operating room with the patient until the surgery is done and the patient is stitched back up. She doesn't start open surgery with one patient and then move on to another operating room where she begins operating on a second patient before the first operation is done. She starts and finishes one operation before starting a second.

  1. Asynchronous: "Start this immediately, but don't wait till it's done. Move on to the next command immediately after you start this command."

Asynchronous example in real life: Ordering food or drinks. First, let's imagine what a synchronous restaurant would look like. A waiter would come to your table, take 1 person's order, rush it back to the kitchen, wait for the kitchen to finish with that person's order, and then bring it back to that person. Only once this first order is taken care of would the waiter then ask the second person at the table for their order. Of course this would be ridiculous. It makes much more sense for a restaurant to process its customers' orders “asynchronously.” That is, after a waiter takes one person's order, he is free to take another person's order before finishing the first order to completion. This allows the restaurant to do multiple things at once, which is ultimately faster because some tasks, like chopping vegetables while you wait for a pot of water to heat, make more sense in parallel than sequence.

Most commands in programming are synchronous. For example, if-statements, setting or changing variables, and calling most Woof methods like rectangle.move(10) are all synchronous commands.

forever is an example of an asynchronous command. Think about it: if forever told the computer to wait until it was done before moving on, the computer would never move on to the next line.

repeat, repeatUntil, every, after are also asynchronous commands.

Asynchronous commands become quite confusing when you want something to happen after an asynchronous command is finished. If you want something after the 10th time you repeat it, you can't just put it on the line below the close of the repeat block. Why? Because the line below repeat happens immediately after the asynchronously command starts, not after it finishes. If at the end of ordering a meal, you ask the waiter to refill your water, you expect him to refill it immediately after sending your order to the kitchen, not after you've received all your food, despite this order coming after the food orders.

But what if, for some perverse reason, you wanted the waiter to wait until after you received your food to refill your water? That is, how do we tell the computer to do something after an asynchronous command is finished? This is different for each programming language, but for WoofJS, repeat and repeatUntil, optionally accept a function as an extra parameter to specify what should happen after the asynchonous command is finished. This is called a "callback" because that function is "called back" and run after the main part of the command is finished.

Also, be careful not to wantonly nest asynchronous commands within each other's main body. For example if you want to make an image move in a square for forever, you can't just put four nested repeats inside a forever. If you put a repeat in a forever, that will cause the computer continuously spawning new repeats really quickly. It's like repeatedly asking a waiter for more and more food before your first course has arrived. The waiter and kitchen will spend so much time processing these thousands of orders, it'll likely cause the restaurant to crash! Instead, in Woof, you have to use recursion and tell your repeat code to start-over only after the 4th repeat is finished finished.

Change color to blue after moving to the right 10 times:

repeat(10, () => {
  NAME.x++;
}, () => {
  NAME.color = "blue";
});

Chaining repeats to slowly draw a square:

repeat(100, () => {
  NAME.angle = RIGHT;
  NAME.move(1);
}, () => {
  repeat(100, () => {
    NAME.angle = UP;
    NAME.move(1);
  }, () => {
    repeat(100, () => {
      NAME.angle = LEFT;
      NAME.move(1);
    }, () => {
      repeat(100, () => {
        NAME.angle = DOWN;
        NAME.move(1);
      });
    });
  });
});

Global Mode

When you include the Woof script in your code, it defaults to creating a full-screen project and polluting your global namespace with Woof's methods. We find not having to type "Woof." over and over again makes a huge difference for beginner programmers, especially those new to typing.

However, if you'd like to turn off this mode, simply add global="false" in your script tag and create your project manually:

var project = new Woof({global: false, width: 300, height: 400});

var IMAGE_NAME = new Woof.Image({project: project, url: "https://i.imgur.com/SMJjVCL.png?1"})

WoofJS was created to be the next step after block-based coding in Scratch. For more details, you can read our announcement post.

About

JavaScript Unleashed

http://woofjs.com

License:MIT License


Languages

Language:JavaScript 100.0%