Skip to content

Instantly share code, notes, and snippets.

@itsbth
Created September 25, 2011 03:55
Show Gist options
  • Save itsbth/1240207 to your computer and use it in GitHub Desktop.
Save itsbth/1240207 to your computer and use it in GitHub Desktop.
WORLD_SIZE = [0..31]
BLOCKS = _([1, 1, 33, 34, 50]).reverse()
Vector = {
add: (a, b) ->
{x: a.x + b.x, y: a.y + b.y}
subtract: (a, b) ->
{x: a.x - b.x, y: a.y - b.y}
multiply: (a, b) ->
{x: a.x * b, y: a.y * b}
}
Texture = {
_textures: {},
_ready: {},
load: (path, id) ->
img = new Image
Texture._ready[id] = false
img.onload = -> Texture._ready[id] = true
img.src = path
Texture._textures[id] = img
get: (id) ->
Texture._textures[id]
ready: (id) ->
if id?
Texture._ready[id]
else
_(Texture._ready).all(_.identity)
}
class Renderer
constructor: (@ctx, @world) ->
@terrain = Texture.get 'terrain'
render: ->
@ctx.clearRect(0, 0, 512, 512)
for x in WORLD_SIZE
for y in WORLD_SIZE
@world.grid[x][y].render @, {x: x, y: y}
for entity in @world.entities
entity.render @
null
drawBlock: (pos, id) ->
[sx, sy] = [(id % 16) * 16, Math.floor(id / 16) * 16]
@ctx.drawImage(@terrain, sx, sy, 16, 16, pos.x * 16, pos.y * 16, 16, 16)
drawSprite: (pos, sheet, id) ->
[sx, sy] = [(id % 9) * 16, Math.floor(id / 9) * 18]
@ctx.drawImage(sheet, sx, sy, 16, 18, pos.x - 8, pos.y - 18, 16, 18)
class World
constructor: ->
@grid = []
@entities = []
tick: ->
for entity in @entities
entity.tick()
generate: ->
noise = new SimplexNoise
for x in WORLD_SIZE
@grid[x] = []
for y in WORLD_SIZE
type = BLOCKS[Math.floor (1 + noise.noise(x / 10, y / 10)) * BLOCKS.length / 2]
if y > 10
@grid[x][y] = new BreakableBlock @, {x: x, y: y}, type, 10
else if y == 10
@grid[x][y] = new BreakableBlock @, {x: x, y: y}, 3, 10
else
@grid[x][y] = new Air @, {x: x, y: y}
create: (type, args...) ->
new type(@, null, args...)
addEntity: (entity) ->
@entities.push entity
replace: (block, new_block) ->
{x, y} = block.pos
@grid[x][y] = new_block
new_block.pos = block.pos
new_block
to_grid: (pos) ->
{x: Math.floor(pos.x / 16), y: Math.floor(pos.y / 16)}
class Entity
constructor: (@world, @pos, @sprite) ->
tick: ->
render: (renderer) ->
class Human extends Entity
constructor: (world, pos) ->
super(world, pos, Texture.get 'human')
@vel = {x: 4, y: 0}
@spc = 0
tick: ->
if @pos.x > 500
@vel.x = -4
else if @pos.x < 12
@vel.x = 4
@vel.y += 5
@pos = Vector.add(@pos, @vel)
@gp = @world.to_grid @pos
if @world.grid[@gp.x][@gp.y].solid
@pos.y = @gp.y * 16
@vel.y = 0
render: (renderer) ->
renderer.drawBlock(@gp, 223)
renderer.drawSprite(@pos, @sprite, (if @vel.x > 0 then 10 else 30) + (@spc++ % 2))
class Block
constructor: (@world, @pos, @id) ->
@solid = true
render: (renderer) ->
renderer.drawBlock(@pos, @id)
click: ->
class Air extends Block
constructor: (world, pos) ->
super(world, pos, -1)
@solid = false
render: (renderer) ->
# do nothing
class BreakableBlock extends Block
constructor: (world, pos, id, @health) ->
super
@max_health = @health
render: (renderer) ->
super
dmg = 10 - Math.floor(@damage() * 10)
renderer.drawBlock(@pos, 239 + dmg) if dmg > 0
click: ->
if @health > 0
@health -= 1
else
@world.replace @, @world.create Air
damage: ->
@health / @max_health
Texture.load 'terrain.png', 'terrain'
Texture.load 'human_base.png', 'human'
world = new World
world.generate()
world.addEntity new Human(world, {x: 30, y: 30})
document.addEventListener 'DOMContentLoaded', ->
canvas = document.getElementById 'cv'
canvas.addEventListener 'click', (evt) ->
x = Math.floor(evt.offsetX / 16)
y = Math.floor(evt.offsetY / 16)
world.grid[x][y].click()
ctx = canvas.getContext '2d'
renderer = new Renderer ctx, world
draw = ->
world.tick()
renderer.render() if Texture.ready()
setTimeout arguments.callee, 100
setTimeout draw, 100
(function() {
var Air, BLOCKS, Block, BreakableBlock, Entity, Human, Renderer, Texture, Vector, WORLD_SIZE, World, world, _i, _results;
var __slice = Array.prototype.slice, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor;
child.__super__ = parent.prototype;
return child;
};
WORLD_SIZE = (function() {
_results = [];
for (_i = 0; _i <= 31; _i++){ _results.push(_i); }
return _results;
}).apply(this);
BLOCKS = _([1, 1, 33, 34, 50]).reverse();
Vector = {
add: function(a, b) {
return {
x: a.x + b.x,
y: a.y + b.y
};
},
subtract: function(a, b) {
return {
x: a.x - b.x,
y: a.y - b.y
};
},
multiply: function(a, b) {
return {
x: a.x * b,
y: a.y * b
};
}
};
Texture = {
_textures: {},
_ready: {},
load: function(path, id) {
var img;
img = new Image;
Texture._ready[id] = false;
img.onload = function() {
return Texture._ready[id] = true;
};
img.src = path;
return Texture._textures[id] = img;
},
get: function(id) {
return Texture._textures[id];
},
ready: function(id) {
if (id != null) {
return Texture._ready[id];
} else {
return _(Texture._ready).all(_.identity);
}
}
};
Renderer = (function() {
function Renderer(ctx, world) {
this.ctx = ctx;
this.world = world;
this.terrain = Texture.get('terrain');
}
Renderer.prototype.render = function() {
var entity, x, y, _j, _k, _l, _len, _len2, _len3, _ref;
this.ctx.clearRect(0, 0, 512, 512);
for (_j = 0, _len = WORLD_SIZE.length; _j < _len; _j++) {
x = WORLD_SIZE[_j];
for (_k = 0, _len2 = WORLD_SIZE.length; _k < _len2; _k++) {
y = WORLD_SIZE[_k];
this.world.grid[x][y].render(this, {
x: x,
y: y
});
}
}
_ref = this.world.entities;
for (_l = 0, _len3 = _ref.length; _l < _len3; _l++) {
entity = _ref[_l];
entity.render(this);
}
return null;
};
Renderer.prototype.drawBlock = function(pos, id) {
var sx, sy, _ref;
_ref = [(id % 16) * 16, Math.floor(id / 16) * 16], sx = _ref[0], sy = _ref[1];
return this.ctx.drawImage(this.terrain, sx, sy, 16, 16, pos.x * 16, pos.y * 16, 16, 16);
};
Renderer.prototype.drawSprite = function(pos, sheet, id) {
var sx, sy, _ref;
_ref = [(id % 9) * 16, Math.floor(id / 9) * 18], sx = _ref[0], sy = _ref[1];
return this.ctx.drawImage(sheet, sx, sy, 16, 18, pos.x - 8, pos.y - 18, 16, 18);
};
return Renderer;
})();
World = (function() {
function World() {
this.grid = [];
this.entities = [];
}
World.prototype.tick = function() {
var entity, _j, _len, _ref, _results2;
_ref = this.entities;
_results2 = [];
for (_j = 0, _len = _ref.length; _j < _len; _j++) {
entity = _ref[_j];
_results2.push(entity.tick());
}
return _results2;
};
World.prototype.generate = function() {
var noise, type, x, y, _j, _len, _results2;
noise = new SimplexNoise;
_results2 = [];
for (_j = 0, _len = WORLD_SIZE.length; _j < _len; _j++) {
x = WORLD_SIZE[_j];
this.grid[x] = [];
_results2.push((function() {
var _k, _len2, _results3;
_results3 = [];
for (_k = 0, _len2 = WORLD_SIZE.length; _k < _len2; _k++) {
y = WORLD_SIZE[_k];
type = BLOCKS[Math.floor((1 + noise.noise(x / 10, y / 10)) * BLOCKS.length / 2)];
_results3.push(y > 10 ? this.grid[x][y] = new BreakableBlock(this, {
x: x,
y: y
}, type, 10) : y === 10 ? this.grid[x][y] = new BreakableBlock(this, {
x: x,
y: y
}, 3, 10) : this.grid[x][y] = new Air(this, {
x: x,
y: y
}));
}
return _results3;
}).call(this));
}
return _results2;
};
World.prototype.create = function() {
var args, type;
type = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
return (function(func, args, ctor) {
ctor.prototype = func.prototype;
var child = new ctor, result = func.apply(child, args);
return typeof result === "object" ? result : child;
})(type, [this, null].concat(__slice.call(args)), function() {});
};
World.prototype.addEntity = function(entity) {
return this.entities.push(entity);
};
World.prototype.replace = function(block, new_block) {
var x, y, _ref;
_ref = block.pos, x = _ref.x, y = _ref.y;
this.grid[x][y] = new_block;
new_block.pos = block.pos;
return new_block;
};
World.prototype.to_grid = function(pos) {
return {
x: Math.floor(pos.x / 16),
y: Math.floor(pos.y / 16)
};
};
return World;
})();
Entity = (function() {
function Entity(world, pos, sprite) {
this.world = world;
this.pos = pos;
this.sprite = sprite;
}
Entity.prototype.tick = function() {};
Entity.prototype.render = function(renderer) {};
return Entity;
})();
Human = (function() {
__extends(Human, Entity);
function Human(world, pos) {
Human.__super__.constructor.call(this, world, pos, Texture.get('human'));
this.vel = {
x: 4,
y: 0
};
this.spc = 0;
}
Human.prototype.tick = function() {
if (this.pos.x > 500) {
this.vel.x = -4;
} else if (this.pos.x < 12) {
this.vel.x = 4;
}
this.vel.y += 5;
this.pos = Vector.add(this.pos, this.vel);
this.gp = this.world.to_grid(this.pos);
if (this.world.grid[this.gp.x][this.gp.y].solid) {
this.pos.y = this.gp.y * 16;
return this.vel.y = 0;
}
};
Human.prototype.render = function(renderer) {
renderer.drawBlock(this.gp, 223);
return renderer.drawSprite(this.pos, this.sprite, (this.vel.x > 0 ? 10 : 30) + (this.spc++ % 2));
};
return Human;
})();
Block = (function() {
function Block(world, pos, id) {
this.world = world;
this.pos = pos;
this.id = id;
this.solid = true;
}
Block.prototype.render = function(renderer) {
return renderer.drawBlock(this.pos, this.id);
};
Block.prototype.click = function() {};
return Block;
})();
Air = (function() {
__extends(Air, Block);
function Air(world, pos) {
Air.__super__.constructor.call(this, world, pos, -1);
this.solid = false;
}
Air.prototype.render = function(renderer) {};
return Air;
})();
BreakableBlock = (function() {
__extends(BreakableBlock, Block);
function BreakableBlock(world, pos, id, health) {
this.health = health;
BreakableBlock.__super__.constructor.apply(this, arguments);
this.max_health = this.health;
}
BreakableBlock.prototype.render = function(renderer) {
var dmg;
BreakableBlock.__super__.render.apply(this, arguments);
dmg = 10 - Math.floor(this.damage() * 10);
if (dmg > 0) {
return renderer.drawBlock(this.pos, 239 + dmg);
}
};
BreakableBlock.prototype.click = function() {
if (this.health > 0) {
return this.health -= 1;
} else {
return this.world.replace(this, this.world.create(Air));
}
};
BreakableBlock.prototype.damage = function() {
return this.health / this.max_health;
};
return BreakableBlock;
})();
Texture.load('terrain.png', 'terrain');
Texture.load('human_base.png', 'human');
world = new World;
world.generate();
world.addEntity(new Human(world, {
x: 30,
y: 30
}));
document.addEventListener('DOMContentLoaded', function() {
var canvas, ctx, draw, renderer;
canvas = document.getElementById('cv');
canvas.addEventListener('click', function(evt) {
var x, y;
x = Math.floor(evt.offsetX / 16);
y = Math.floor(evt.offsetY / 16);
return world.grid[x][y].click();
});
ctx = canvas.getContext('2d');
renderer = new Renderer(ctx, world);
draw = function() {
world.tick();
if (Texture.ready()) {
renderer.render();
}
return setTimeout(arguments.callee, 100);
};
return setTimeout(draw, 100);
});
}).call(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment