JogoShugh / SpaceMiner

SpaceMiner
http://spaceminer.azurewebsites.net
Other
4 stars 4 forks source link

Need shortcuts for game rules without tons of function syntax or quoted values #49

Closed JogoShugh closed 9 years ago

JogoShugh commented 9 years ago

Following up from #48, this syntax is too much for getting going quickly:

let rules = [
  {
    score: 2000,
    then: () => {
      box({sprite:'e'});
      wall({
        dir:'d',
        start: {x:5, y:1}
      });
    }
  }
];

Here are some possible shortcuts:

Examples:

rules(
  rule(
    when(score(2000)),
,   then(box())),
  ),
  rule(
    when(score(4000)), 
    then(box( e, pt(5,5), size(5) ))
 )
)

Now the problem becomes () soup like lisp.

Perhaps for very simple rules the above could boil down to:

rules(
  score(2000, box(5, 5, 5)),   // When score is 2000, create a box at x:5, y:5 of size 5, defaulting to T
  score(4000, wall(1, 5, g)),  // When score is 4000, create a wall at x:1, y:5, filled with gems
  score(6000, wall( x(1),  y(5), down, length(5), gem ) ),  // When score is 6000, create a wall at x:1, y:5, go down a length of 5 fill it with gemes
  score(6000, wall( y(5), x(1), gem, length(5), down ) ), // same as above
  score(6000, wall(gem)).and( box(enemy) ) // Create a wall of gems across the top, and a box of enemies
)

If we do it like this, then box, wall, block, etc have to no longer immediately invoke behavior, but they need to become functions that return functions.

JogoShugh commented 9 years ago

Here's a working cut at some syntax above, on nitrous you can paste this into a Training level and see it in action, just be sure to Reset if you execute and then want to modify the rules, because realized rules only run once, and are only realized once per game instance.

let _rules = [];

let at = (x=1, y=1) => ({start:{x:x, y:y}});

let sprite = (shortName='t') => ({sprite:shortName});
let g, gem, e, enemy, c, coin, t, tile, p, player;
g = gem = () => sprite('g');
e = enemy = () => sprite('e');
c = coin = () => sprite('c');
t = tile = () => sprite('t');
p = player= () => sprite('p');

let dir = (direction='d') => ({dir:direction});
let d, down, u, up, l, left, r, right;
d = down = () => dir('d');
u = up = () => dir('u');
l = left = () => dir('l');
r = right = () => dir('r');

let shapeDefer = shape => {
  return (...opts) => {
    let props = {};
    for (let opt of opts) {
      Object.assign(props, opt);
    }
    return () => window[shape](props);
  }
};

['box', 'block', 'wall'].map((shape) => window['_' + shape] = shapeDefer(shape))

let length, size, height, width;
length = size = height = width = (dimension) => ({size:dimension});

let score = (...opts) => {
  let props = {};
  if (!opts.length > 1) throw "Must pass at least two arguments to score(...) function";
  // Assume number here:
  let scoreMin = parseInt(opts.shift());
  props.score = scoreMin;
  props.then = () => {};
  if (opts.length > 0) {
    props.then = () => {
      for(let fun of opts) {
        if (typeof fun === 'function') fun();
      }
    };
  }
  return props;
};

let rules = (..._rules) => _rules;

game.world.rules = rules(
  score(400, _box(gem(), size(5), at(2,2))),
  score(1000, 
    _wall(enemy(), at(4,1)),
    _wall(tile(), at(4,4), left())   
  )
);
JogoShugh commented 9 years ago

We can now build worlds with simplified rules syntax like this:

var worldName = "World with addRules!";
var explorerName = "Rule Breakmaker";

addRules(
  score(400, box(gem, size(5), at(2,2))),
  score(1000,
    wait(3000,
      wall(enemy, at(4,1)),
      wall(tile, left, at(4,4))
    )
  )
);

This creates two rules:

This is implemented as a bunch of tiny functions that produce functions which produce tiny objects with properties pointing the values needed by the lower-level rules execution class in Rule, defined in game.next.js.

JogoShugh commented 9 years ago

Can now do it this way, a great simplification. This makes building an initial game simpler than even learning HTML or CSS:

setup(
    enemies.yellow,
    tiles.speckled,
    players.dark,
    coins.brown,
    gems.ruby
)

start(
    fill(coin),
    wall(at(1,9)),
    block(gem, at(5,5)),
    box(gem, at(10,1)),
    block(at(11,2), size(2)),
    sprite(player, at(10, 10)),
    sprite(gem, at(10,12)),
    sprite(enemy, at(10, 5))
)

rules(
    score(4000, wall(at(1,9), down, coin)),
    score(8000, wall(at(1,9), down))
)