-
Notifications
You must be signed in to change notification settings - Fork 5
Getting Started
Just getting started? Let's do this!!
Node is a native javascript interpreter, so you write javascript for not only the browser but also the terminal. You can install it from the binaries provided at www.nodejs.org. You can also install it via homebrew or aptitude, but be warned this will install it as nodejs
and not node
.
To test that you've installed everything correctly, try to access it from the terminal.
$ node --version
5.x.x
$ npm --version
3.x.x
If they print out their versions, then you've successfully installed them. But if you get any errors, your node
or npm
might not be in your PATH
.
Git is a version control system. We use it to handle saving and sharing your code. It integrates with Github, so you can push you code here. You can install it via www.git-scm.com.
To test that you've installed everything correctly, try to access it from the terminal.
$ git --version
2.x.x
Chrome is an awesome browser. And although our game will be playable on all the browsers, we particularly support Chrome, since we're bundling the game with the chromium executable. You can install it via www.google.com/chrome.
Atom is an awesome editor. If you don't have a plain-text editor yet, now is a good time to install one! You can use whatever you want, but I recommend Atom. But again, you can use whatever you're most comfortable with.
You need an account. You can signup for free. If you're a student, you can get upgrade to an academic account through the Student Developer Package.
After forking this repository, you'll have your own copy of the code at https://github.com/yourusername/enchiridion.
On your computer, clone your repository.
$ git clone https://github.com/yourusername/enchiridion
Remember to clone from your fork, using your username!
$ get checkout getting-started
This is a branch prepared for this guide.
npm install
node build server
Got some errors? It happens.
Check that you're not using an outdated version of Node. Some package managers are distributing outdated versions of Node. You can see what version of node you have by running node --version
. We support anything greater than or equal to v0.12. If you are running an outdated version, you can install nvm to handle version-switching.
Delete your node_modules
directory, and run npm install
again.
If none of that helps, leave a comment on this gist and I'll fix it as fast as I can.
Open up index.js
. Type:
console.log("Hello World")
HOLY SHIT it logged it!
Note that, while the build server is running, any changes you make to any of the files are reflected immediately on the page via reloading the page. So it's nice to do a half-and-half environment flow, so you can see both the page and your editor.
Okay, let's get some React up in here! But first we need to install it.
$ npm install --save-dev react
$ npm install --save-dev react-dom
And then import it into our script.
var React = require("react")
var ReactDOM = require("react-dom")
And now we can use it!
var mount = (
<div>
<h1>Hello World!</h1>
<h3>How are you today?</h3>
</div>
)
ReactDOM.render(mount, document.getElementById("mount"))
What?! HTML in Javascript??
That's right! With a bit of React, we can programmatically generate HTML! It should something like this:
The coolest part of React, though, is that we can define our own custom components, which are composed of other bits of HTML, CSS and JS, which we can reuse throughout our code. Included in the getting-started
branch is some code like that, which lives in the ./scripts/render
directory.
var AspectRatioFrame = require("./scripts/render/AspectRatioFrame.js")
var mount = (
<AspectRatioFrame width={320} height={180}>
<h1>Hello World!</h1>
<h3>How are you today?</h3>
</AspectRatioFrame>
)
Which should look something like this:
The AspectRatioFrame
component, when given a width and height, will resize itself (and all of the content inside of it) to fit the screen, while maintaining those dimensions. Handy, huh?
Also provided is the Entity
component, which we'll be using for just about everything.
var Entity = require("./scripts/render/Entity.js")
var AspectRatioFrame = require("./scripts/render/AspectRatioFrame.js")
var mount = (
<AspectRatioFrame width={320} height={180}>
<Entity/>
</AspectRatioFrame>
)
Do you see a little untextured square in the corner? That's an entity! And just like the AspectRatioFrame
, we can pass parameters to Entity
.
var adventurer = {
position: {x: 2, y: 2},
color: "#C00",
}
var mount = (
<AspectRatioFrame width={320} height={180}>
<Entity data={adventurer}/>
</AspectRatioFrame>
)
We can position the entity along our grid using the position
attribute, and color the entity using the color
attribute. A full list of all the attributes that the Entity
component supports are detailed in the documentation.
So my favorite part of React is how we can declaratively establish how we want to render the game using our HTML. And from then on, we can just manipulate the state of the game using JS, and it'll automatically update the HTML!
Buuuuut as it stands right now, the HTML we're generating is static; we can't update it. We need to convert HTML to a dynamic component, like this:
var Mount = React.createClass({
render: function() {
return (
<AspectRatioFrame width={320} height={180}>
<Entity data={adventurer}/>
</AspectRatioFrame>
)
}
})
var render = ReactDOM.render(<Mount/>, document.getElementById("mount"))
And now that it's dynamic react, and not static react, we can use it as a component, like we did with AspectRatioFrame
and Entity
. Which is important for our game loop.
So up at the top of the page, import Afloop.
var Afloop = require("afloop")
And then make a loop.
var loop = new Afloop(function() {
adventurer.position.x += 0.1
render.forceUpdate()
})
Up at the top, import Keyb.
var Keyb = require("keyb")
And use it in the loop.
var loop = Afloop(function() {
if(Keyb.isJustDown("<up>")) {
adventurer.position.y -= 1
} if(Keyb.isJustDown("<down>")) {
adventurer.position.y += 1
} if(Keyb.isJustDown("<left>")) {
adventurer.position.x -= 1
} if(Keyb.isJustDown("<right>")) {
adventurer.position.x += 1
}
render.forceUpdate()
})
We don't want a boring square forever. Let's import an image!
var image = require("./images/shapes/entities/0.png")
console.log(image)
Which will log something like this:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAYAQMAAADJbu9PAAAABlBMV…DUP2Eo/sNQfI+h+AlIpPwDg9oHBp4fDDw1DBwKDBIGyDoBN70Pb2m0Lv0AAAAASUVORK5CYII=
This is a Data URI, a base-64 encoded version of our image! We can pass this to entity to give it an image.
var adventurer = {
position: {x: 2, y: 2},
shape: require("./images/shapes/entities/0.png"),
color: "#C00",
}
The graphics were put together at the Oryx Design Lab, and we use them as a mask.
But we're not done yet, we can also add a transition property
var adventurer = {
position: {x: 2, y: 2},
shape: require("./images/shapes/entities/0.png"),
transition: {duration: 0.2},
color: "#C00",
}
And now, whenever the entity is moved, they take 0.2 seconds to transition between their positions.
So, like, ECMA6 came out, and I was all like:
Because now we can use proper javascript classes. Like so:
class Adventurer {
constructor() {
this.position = {x: 2, y: 2}
this.shape = require("./images/shapes/entities/0.png")
this.transition = {duration: 0.2}
this.color = "#C00"
}
}
var adventurer = new Adventurer()
This refactor affords us a lot, because now we can instantiate multiple instances of a given class (like monsters), employ encapsulation to handle data, and extend classes via inheritance.
We can also refactor our updating function as a method of our class.
class Adventurer {
constructor() {
this.position = {x: 2, y: 2}
this.shape = require("./images/shapes/entities/0.png")
this.transition = {duration: 0.2}
this.color = "#C00"
}
update() {
if(Keyb.isJustDown("<up>")) {
this.position.y -= 1
} if(Keyb.isJustDown("<down>")) {
this.position.y += 1
} if(Keyb.isJustDown("<left>")) {
this.position.x -= 1
} if(Keyb.isJustDown("<right>")) {
this.position.x += 1
}
}
}
var loop = Afloop(function() {
adventurer.update()
render.forceUpdate()
})
Aaaaand you're done! Good work!
What's next? Time to start Contributing!