Created
September 25, 2011 03:55
-
-
Save itsbth/1240207 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
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 |
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
(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