Last active
December 14, 2015 10:49
-
-
Save Raynos/5075037 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var coreduction = require("coreduction") | |
var map = require("reducers/map") | |
var reductions = require("reducers/reductions") | |
var fold = require("reducers/fold") | |
// These are inputs. Inputs are Streams / Events / | |
// Signals / Behaviours | |
// Inputs aren't hard to write, they just wrap lower level host | |
// environments and create a streaming representation of their | |
// current state | |
var KeyboardArrows = require("../lib/keyboard-arrows") | |
var WindowDimension = require("../lib/window-dimension") | |
var fps = require("../lib/fps") | |
// named color variables | |
var skyblue = rgb(174, 238, 238) | |
var grassgreen = rgb(74, 163, 41) | |
/* Your app has a state representation. This is something that | |
gets passed to update and update returns a new representation | |
of current state based on input changes. | |
This state representation also get's passed to display | |
which maps it to a data structure for Renderable display | |
items. | |
*/ | |
// ---- Model ---- | |
var mario = { x: 0, y: 0, vx: 0, vy: 0 } | |
/* Your actual app consists of constructing the input sources | |
for your app. | |
Calling foldp(input, update, initialState) which will | |
return a stream of states by calling | |
`update(currentState, changeInInput)` | |
Thus `marioState` is a stream of current states. | |
We then lift two streams `WindowDimension` and `marioState` | |
through the display function which will transform the | |
current state into a renderable data structure. It also | |
depends on the window dimension so that the display | |
gets resized correctly. | |
We then call `render(main)` which does the hard machinery of | |
efficiently rendering our declarative rendering structures | |
by doing clever creation of DOM / SVG / Canvas and clever | |
partial updating. | |
*/ | |
// ---- Game ---- | |
var input = lift2(fps(30), KeyboardArrows, function (dt, arrows) { | |
return { dt: dt, arrows: arrows } | |
}) | |
var marioState = foldp(input, update, mario) | |
var main = lift2(WindowDimension, marioState, display) | |
/* magic :D. Render will diff your current renderable data structure | |
with the last and do a partial mutable update */ | |
render(main) | |
/* The display function is in charge turn current state into | |
something that can be rendered | |
In this case we grab a correct gif for how mario should look | |
and then render him in the correct position based on his | |
x & y. | |
We also render the sky and grass as rectangles | |
*/ | |
// ---- Display ---- | |
function display(windowDimension, mario) { | |
var w = windowDimension.w | |
var h = windowDimension.h | |
var verb = mario.y > 0 ? "jump" : | |
mario.vx !== 0 ? "walk" : "stand" | |
var direction = mario.vx < 0 ? "left" : "rigth" | |
var src = "/imgs/mario/" + verb + "/" + direction + ".gif" | |
var largeRect = rect(h, { x: half(w), y: half(h) }) | |
var smallRect = rect(50, { x: half(w), y: 25 }) | |
var sky = filled(largeRect, skyblue) | |
var grass = filled(smallRect, grassgreen) | |
var marioImage = image(35, 35, src) | |
var marioForm = toForm(marioImage, { | |
x: mario.x | |
, y: (h - 63) - mario.y | |
}) | |
return collage(w, h, [sky, grass, marioForm]) | |
function half(n) { | |
return n / 2 | |
} | |
} | |
/* The update logic determines how the model / state changes | |
based on inputs | |
It consists of applying the jumping logic which just sets | |
mario's y velocity if he's allowed to jump. | |
Then applying gravity which decrements his y velocity for | |
every tick of the fps counter | |
Then we apply the walking logic which just sets his x velocity | |
based on whether left or right is pressed. | |
Then finally we move him which updates his x, y position based | |
on velocities | |
*/ | |
// ---- Update ---- | |
function update(mario, tuple) { | |
var dt = tuple.dt | |
var arrows = tuple.dt | |
var jumpedMario = jump(mario, arrows) | |
var gravityMario = gravity(jumpedMario, dt) | |
var walkedMario = walk(gravityMario, arrows) | |
return move(walkedMario, dt) | |
} | |
function gravity(mario, dt) { | |
return { | |
vy: mario.vy - (dt / 700) | |
, vx: mario.vx | |
, x: mario.x | |
, y: mario.y | |
} | |
} | |
function jump(mario, arrows) { | |
if (arrows.y > 0 && mario.y === 0) { | |
return { | |
vy: 0.5 | |
, vx: mario.vx | |
, x: mario.x | |
, y: mario.y | |
} | |
} else { | |
return mario | |
} | |
} | |
function walk(mario, arrows) { | |
return { | |
vx: arrows.x / 20 | |
, vy: mario.vy | |
, x: mario.x | |
, y: mario.y | |
} | |
} | |
function move(mario, dt) { | |
return { | |
x: mario.x + dt * mario.vx | |
, y: max(0, mario.y + dt * mario.yx) | |
, vx: mario.vx | |
, vy: mario.vy | |
} | |
} | |
/* Returns a data structure for rendering image */ | |
function image(width, height, src) { | |
// figure out a good data structure for an image | |
} | |
/* Returns a form data structure to render an arbitary elem at | |
that co-ordinate | |
*/ | |
function toForm(elem, coords) { | |
// figure out a good data structure for Form & Element | |
} | |
/* Returns a data structure that can be rendered as a rectangle | |
*/ | |
function rect(size, center) { | |
// figure out a good data structure for Rect (which is a Form) | |
} | |
/* Return a shape filled in with said color | |
*/ | |
function filled(shape, color) { | |
// figure out how to set color on Shape data structure | |
} | |
/* collage creates a scene of size width x height and renders | |
the list of shapes inside it. | |
*/ | |
function collage(width, height, shapes) { | |
// WORK IN PROGRESS | |
// Figure out good data structure for a Collage of { height, width, manyForms } | |
return { | |
values: [width, height] | |
, render: render | |
, update: update | |
, children: [shapes] | |
, is: "Renderable" | |
} | |
function render(width, height) { | |
/*global document*/ | |
var surface = document.createElement("svg") | |
surface.width = width | |
surface.height = height | |
return surface | |
} | |
function update(surface, width, height) { | |
surface.width = width | |
surface.height = height | |
} | |
} | |
/* main is a stream of lazy elements, shapes and forms. | |
It's `render`'s job to efficiently render them | |
It should just do a diff between curr and prev and either create | |
or update things | |
*/ | |
function render(main) { | |
// WORK IN PROGRESS | |
// THIS NEEDS TO RENDER EVERY RENDERABLE DATA STRUCTURE | |
// IT ALSO NEEDS TO DO CLEVER PARTIAL UPDATES | |
// THIS IS HARD | |
var mains = reductions(main, function (prev, curr) { | |
var render = curr[0] | |
var update = curr[1] | |
}, null) | |
fold(mains, function () {}) | |
} | |
function foldp(input, f, initial) { | |
return reductions(input, f, initial) | |
} | |
function lift2(a, b, mapper) { | |
return map(coreduction(a, b), function (tuple) { | |
return mapper(tuple[0], tuple[1]) | |
}) | |
} | |
function max(x, y) { | |
return x > y ? x : y | |
} | |
function rgb(r, g, b) { | |
return { r: r, g: g, b: b } | |
} |
It may actually be quite straightforward to reuse the logic from core-js/Graphics/Render.js and core-js/Graphics/Collage.js
All those single-space tabbed files make me :O
@jez0990 curr[0]
and curr[1]
are not things. I don't know what the data structure should look like.
And yes most of Graphics could be ported but then you have to port the entire thing + commonJS it.
I should talk to evan about taking Graphics out as a seperate open source JS thing
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hmm. I'm lost at understanding how curr[0] and curr[1] get assigned. I don't suppose curr[2] is marioState?
Also, on line 78 you've got "rigth"
I don't have enough smarts to actually help with this just yet :/