diff --git a/build-games.sh b/build-games.sh new file mode 100755 index 0000000..341b0e9 --- /dev/null +++ b/build-games.sh @@ -0,0 +1,7 @@ +for f in gemswap/source/*.svg +do + name=${f%%.*} + name=${name##*/} + echo "Processing $f..." + inkscape --export-png=gemswap/assets/images/$name.png $f +done diff --git a/compiled/radium.js b/compiled/radium.js new file mode 100644 index 0000000..259a884 --- /dev/null +++ b/compiled/radium.js @@ -0,0 +1,894 @@ +// Generated by CoffeeScript 1.7.1 +(function() { + var Engine, Object, ResourceManager, Scene, Sound, Sprite, Tileset, TilesetTile, util, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __slice = [].slice; + + window.pass = void 0; + + Engine = (function() { + function Engine(resource_manager) { + this.resource_manager = resource_manager; + this.getTileset = __bind(this.getTileset, this); + this.getSprite = __bind(this.getSprite, this); + this.getSound = __bind(this.getSound, this); + this.getObject = __bind(this.getObject, this); + this.getScene = __bind(this.getScene, this); + this.createTileset = __bind(this.createTileset, this); + this.createSprite = __bind(this.createSprite, this); + this.createSound = __bind(this.createSound, this); + this.createObject = __bind(this.createObject, this); + this.createScene = __bind(this.createScene, this); + this.setPreloadScene = __bind(this.setPreloadScene, this); + this.setInitialScene = __bind(this.setInitialScene, this); + this.iteration = __bind(this.iteration, this); + this.loop = __bind(this.loop, this); + this.start = __bind(this.start, this); + this.updateCanvasSize = __bind(this.updateCanvasSize, this); + this.getSurface = __bind(this.getSurface, this); + this.createSurface = __bind(this.createSurface, this); + this.addCanvas = __bind(this.addCanvas, this); + this.canvases = {}; + this.fps = 45; + this.last_frameskip_collection = Math.floor(Date.now()); + this.frameskip = 0; + this.current_frameskip = 0; + this.scenes = {}; + this.objects = {}; + this.sounds = {}; + this.sprites = {}; + this.tilesets = {}; + } + + Engine.prototype.addCanvas = function(canvas, label) { + if (label == null) { + label = ""; + } + return this.canvases[label] = util.unpackElement(canvas); + }; + + Engine.prototype.createSurface = function(label) { + return this.canvases[label] = document.createElement("canvas"); + }; + + Engine.prototype.getSurface = function(label) { + var _ref; + if (typeof label === "string") { + return (_ref = this.canvases[label]) != null ? _ref.getContext("2d") : void 0; + } else if (label.tagName === "CANVAS") { + return label.getContext("2d"); + } else { + return label; + } + }; + + Engine.prototype.updateCanvasSize = function(canvas, w, h) { + canvas.width = w; + canvas.height = h; + canvas.style.width = "" + w + "px"; + return canvas.style.height = "" + h + "px"; + }; + + Engine.prototype.start = function() { + this.initial_scene.addTargetSurface(this.canvases[""]); + return this.loop(); + }; + + Engine.prototype.loop = function() { + return this.iteration(); + }; + + Engine.prototype.iteration = function() { + var belated_timeout, current_frame, frame_interval, name, next_frame, overtime, scene, _ref; + frame_interval = 1000 / this.fps; + current_frame = Date.now(); + next_frame = current_frame + frame_interval; + if (Math.floor(current_frame) > this.last_frameskip_collection) { + this.frameskip = this.current_frameskip; + this.current_frameskip = 0; + this.last_frameskip_collection = Math.floor(current_frame); + } + _ref = this.scenes; + for (name in _ref) { + scene = _ref[name]; + if (scene.active) { + scene.iteration(); + } + } + if (Date.now() < next_frame) { + return setTimeout(this.iteration, next_frame - Date.now()); + } else { + overtime = Date.now() - next_frame; + this.current_frameskip += Math.floor(overtime / frame_interval); + belated_timeout = overtime % frame_interval; + return setTimeout(this.iteration, belated_timeout); + } + }; + + Engine.prototype.setInitialScene = function(scene) { + return this.initial_scene = scene; + }; + + Engine.prototype.setPreloadScene = function(scene) { + return this.preload_scene = scene; + }; + + Engine.prototype.createScene = function(name) { + var scene; + scene = new Scene(this, name); + if (this.initial_scene == null) { + this.initial_scene = scene; + } + return this.scenes[name] = scene; + }; + + Engine.prototype.createObject = function(name) { + return this.objects[name] = new Object(this, name); + }; + + Engine.prototype.createSound = function(name, sound) { + return this.sounds[name] = new Sound(this, name, this.resource_manager.getSound(sound)); + }; + + Engine.prototype.createSprite = function(name, image) { + console.log("gget", this.resource_manager.getImage(image)); + return this.sprites[name] = new Sprite(this, name, this.resource_manager.getImage(image)); + }; + + Engine.prototype.createTileset = function(name, image, tile_width, tile_height) { + return this.tilesets[name] = new Tileset(this, name, this.resource_manager.getImage(image), tile_width, tile_height); + }; + + Engine.prototype.getScene = function(name) { + if (typeof name === "string") { + return this.scenes[name]; + } else { + return name; + } + }; + + Engine.prototype.getObject = function(name) { + if (typeof name === "string") { + return this.objects[name]; + } else { + return name; + } + }; + + Engine.prototype.getSound = function(name) { + if (typeof name === "string") { + return this.sounds[name]; + } else { + return name; + } + }; + + Engine.prototype.getSprite = function(name) { + if (typeof name === "string") { + return this.sprites[name]; + } else { + return name; + } + }; + + Engine.prototype.getTileset = function(name) { + if (typeof name === "string") { + return this.tilesets[name]; + } else { + return name; + } + }; + + return Engine; + + })(); + + Engine.prototype.draw = { + _startPath: (function(_this) { + return function(surface, options) { + var _ref; + surface = _this.getSurface(surface); + if ((_ref = !options._is_text) != null ? _ref : false) { + surface.beginPath(); + } + return surface; + }; + })(this), + _finishPath: (function(_this) { + return function(surface, options) { + var _ref, _ref1, _ref10, _ref11, _ref12, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9; + if ((_ref = options.stroke) != null ? _ref : true) { + surface.lineWidth = (_ref1 = (_ref2 = options.lineWidth) != null ? _ref2 : (_ref3 = options.pen) != null ? _ref3.lineWidth : void 0) != null ? _ref1 : 1; + surface.strokeStyle = (_ref4 = (_ref5 = options.lineColor) != null ? _ref5 : (_ref6 = options.pen) != null ? _ref6.lineColor : void 0) != null ? _ref4 : "black"; + if ((_ref7 = options._is_text) != null ? _ref7 : false) { + surface.strokeText(options.text, options.x, options.y); + } else { + surface.stroke(); + } + } + if ((_ref8 = options.fill) != null ? _ref8 : false) { + surface.fillStyle = (_ref9 = (_ref10 = options.fillColor) != null ? _ref10 : (_ref11 = options.pen) != null ? _ref11.fillColor : void 0) != null ? _ref9 : "white"; + if ((_ref12 = options._is_text) != null ? _ref12 : false) { + return surface.fillText(options.text, options.x, options.y); + } else { + return surface.fill(); + } + } + }; + })(this), + _getTextWidth: (function(_this) { + return function(surface, text, options) { + var width; + _this._applyTextContext(surface, options); + width = surface.measureText(text).width; + surface.restore(); + return width; + }; + })(this), + _applyTextContext: (function(_this) { + return function(surface, options) { + var font_family, font_size, font_style, font_weight, scale, _ref, _ref1, _ref2, _ref3, _ref4, _ref5; + font_family = (_ref = options.font) != null ? _ref : "sans-serif"; + font_size = (_ref1 = options.size) != null ? _ref1 : 16; + font_weight = (_ref2 = options.weight) != null ? _ref2 : "normal"; + font_style = (_ref3 = options.style) != null ? _ref3 : "normal"; + scale = (_ref4 = options.scale) != null ? _ref4 : 1; + surface.save(); + surface.font = "" + font_weight + " " + font_style + " " + font_size + "px '" + font_family + "'"; + surface.globalAlpha = (_ref5 = options.alpha) != null ? _ref5 : 1; + return surface.scale(scale, scale); + }; + })(this), + line: (function(_this) { + return function(x1, y1, x2, y2, options, surface) { + if (options == null) { + options = {}; + } + if (surface == null) { + surface = ""; + } + surface = _this._startPath(surface, options); + surface.moveTo(x1, y1); + surface.lineTo(x2, y2); + return _this._finishPath(surface, options); + }; + })(this), + rectangle: (function(_this) { + return function(x1, y1, x2, y2, options, surface) { + if (options == null) { + options = {}; + } + if (surface == null) { + surface = ""; + } + surface = _this._startPath(surface, options); + surface.rect(x1, y1, x2 - x1, y2 - y1); + return _this._finishPath(surface, options); + }; + })(this), + boxEllipse: (function(_this) { + return function(x1, y1, x2, y2, options, surface) { + var rx, ry, x, y; + if (options == null) { + options = {}; + } + if (surface == null) { + surface = ""; + } + x = (x1 + x2) / 2; + y = (y1 + y2) / 2; + rx = (x2 - x1) / 2; + ry = (y2 - y1) / 2; + return _this.radiusEllipse(x, y, rx, ry, options, surface); + }; + })(this), + radiusEllipse: (function(_this) { + return function(x, y, rx, ry, options, surface) { + var i, step, _i, _ref, _ref1; + if (options == null) { + options = {}; + } + if (surface == null) { + surface = ""; + } + surface = _this._startPath(surface, options); + step = (_ref = options.step) != null ? _ref : 0.1; + if (rx === ry) { + surface.arc(x, y, rx, 0, 2 * Math.PI, false); + } else { + surface.moveTo(x + rx, y); + for (i = _i = 0, _ref1 = Math.PI * 2 + step; 0 <= _ref1 ? _i <= _ref1 : _i >= _ref1; i = 0 <= _ref1 ? ++_i : --_i) { + surface.lineTo(x + (Math.cos(i) * rx), y + (Math.sin(i) * ry)); + } + } + return _this._finishPath(surface, options); + }; + })(this), + boxPolygon: (function(_this) { + return function(x1, y1, x2, y2, sides, options, surface) { + if (options == null) { + options = {}; + } + if (surface == null) { + surface = ""; + } + return pass; + }; + })(this), + radiusPolygon: (function(_this) { + return function(x, y, r, sides, options, surface) { + if (options == null) { + options = {}; + } + if (surface == null) { + surface = ""; + } + return pass; + }; + })(this), + text: (function(_this) { + return function(x, y, text, options, surface) { + var text_width; + if (options == null) { + options = {}; + } + if (surface == null) { + surface = ""; + } + if (options.alignment == null) { + options.alignment = "left"; + } + if (options.scale == null) { + options.scale = 1; + } + options._is_text = true; + options.text = text; + options.y = y; + if (options.fill == null) { + options.fill = true; + } + if (options.fillColor == null) { + options.fillColor = "black"; + } + if (options.stroke == null) { + options.stroke = false; + } + if (alignment === "left") { + options.x = x; + } else { + text_width = _this._getTextWidth(text, options); + if (alignment === "center") { + options.x = x - ((text_width / 2) * scale * scale); + } else if (alignment === "right") { + options.x = x - text_width; + } + } + _this._startPath(surface, options); + _this._finishPath(surface, options); + return surface.restore(); + }; + })(this) + }; + + Engine.prototype.random = { + number: (function(_this) { + return function(min, max, precision) { + var base_number, rounding_factor, space; + base_number = Math.random(); + space = Math.abs(ceiling - floor); + rounding_factor = 1 / (precision != null ? precision : 0.00000001); + return Math.floor((min + (base_number * space)) * rounding_factor) / rounding_factor; + }; + })(this), + pick: (function(_this) { + return function() { + var options; + options = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return options[Math.floor(Math.random() * options.length)]; + }; + })(this), + string: (function(_this) { + return function(length, alphabet) { + var i; + if (alphabet == null) { + alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + } + return ((function() { + var _i, _ref, _results; + _results = []; + for (i = _i = 0, _ref = length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) { + _results.push(alphabet[Math.floor(Math.random() * alphabet.length)]); + } + return _results; + })()).join(""); + }; + })(this) + }; + + Object = (function() { + function Object(engine, name) { + this.engine = engine; + this.name = name; + this.checkPointCollision = __bind(this.checkPointCollision, this); + this.getBoundingBox = __bind(this.getBoundingBox, this); + this.drawSprite = __bind(this.drawSprite, this); + this.drawSelf = __bind(this.drawSelf, this); + this.callEvent = __bind(this.callEvent, this); + this.sprite = null; + this.x = 0; + this.y = 0; + } + + Object.prototype.callEvent = function(name, data) { + var _ref; + if (data == null) { + data = {}; + } + switch (name) { + case "create": + return typeof this.onCreate === "function" ? this.onCreate(data) : void 0; + case "step": + return typeof this.onStep === "function" ? this.onStep(data) : void 0; + case "draw": + this.drawSelf((_ref = data.surface) != null ? _ref : ""); + return typeof this.onDraw === "function" ? this.onDraw(data) : void 0; + } + }; + + Object.prototype.drawSelf = function(surface) { + return this.drawSprite(surface); + }; + + Object.prototype.drawSprite = function(surface) { + var _ref; + if (surface == null) { + surface = ""; + } + if ((this.sprite != null) && ((_ref = this.draw_sprite) != null ? _ref : "true")) { + return this.sprite.draw(this.x, this.y, {}, surface); + } + }; + + Object.prototype.getBoundingBox = function() { + var image_size, _ref; + image_size = (_ref = this.sprite) != null ? _ref.getSize() : void 0; + return { + x1: this.x, + x2: this.x + (image_size != null ? image_size.width : void 0), + y1: this.y, + y2: this.y + (image_size != null ? image_size.height : void 0) + }; + }; + + Object.prototype.checkPointCollision = function(x, y) { + var bounding_box; + bounding_box = this.getBoundingBox(); + return x >= (bounding_box != null ? bounding_box.x1 : void 0) && x <= (bounding_box != null ? bounding_box.x2 : void 0) && y >= (bounding_box != null ? bounding_box.y1 : void 0) && y <= (bounding_box != null ? bounding_box.y2 : void 0); + }; + + return Object; + + })(); + + ResourceManager = (function() { + function ResourceManager(base_path) { + this.base_path = base_path != null ? base_path : ""; + this.preload = __bind(this.preload, this); + this.prepare = __bind(this.prepare, this); + this.getImage = __bind(this.getImage, this); + this.addSounds = __bind(this.addSounds, this); + this.addScripts = __bind(this.addScripts, this); + this.addImages = __bind(this.addImages, this); + this.addScript = __bind(this.addScript, this); + this.addSound = __bind(this.addSound, this); + this.addImage = __bind(this.addImage, this); + this.joinPath = __bind(this.joinPath, this); + this.resources = { + stage1_images: [], + stage1_audio: [], + stage1_scripts: [], + images: [], + audio: [], + scripts: [] + }; + this.resource_objects = { + images: {}, + audio: {}, + scripts: {} + }; + } + + ResourceManager.prototype.joinPath = function(path) { + if (this.base_path === "") { + return path; + } else { + return util.stripRight(this.base_path, "/") + "/" + path; + } + }; + + ResourceManager.prototype.addImage = function(path, first_stage) { + if (first_stage == null) { + first_stage = false; + } + if (first_stage) { + return this.resources.stage1_images.push(this.joinPath(path)); + } else { + return this.resources.images.push(this.joinPath(path)); + } + }; + + ResourceManager.prototype.addSound = function(path, first_stage) { + if (first_stage == null) { + first_stage = false; + } + if (first_stage) { + return this.resources.stage1_audio.push(this.joinPath(path)); + } else { + return this.resources.audio.push(this.joinPath(path)); + } + }; + + ResourceManager.prototype.addScript = function(path, first_stage) { + if (first_stage == null) { + first_stage = false; + } + if (first_stage) { + return this.resources.stage1_scripts.push(this.joinPath(path)); + } else { + return this.resources.scripts.push(this.joinPath(path)); + } + }; + + ResourceManager.prototype.addImages = function(paths, first_stage) { + var path, _i, _len, _results; + if (first_stage == null) { + first_stage = false; + } + _results = []; + for (_i = 0, _len = paths.length; _i < _len; _i++) { + path = paths[_i]; + _results.push(this.addImage(path, first_stage)); + } + return _results; + }; + + ResourceManager.prototype.addScripts = function(paths, first_stage) { + var path, _i, _len, _results; + if (first_stage == null) { + first_stage = false; + } + _results = []; + for (_i = 0, _len = paths.length; _i < _len; _i++) { + path = paths[_i]; + _results.push(this.addScript(path, first_stage)); + } + return _results; + }; + + ResourceManager.prototype.addSounds = function(paths, first_stage) { + var path, _i, _len, _results; + if (first_stage == null) { + first_stage = false; + } + _results = []; + for (_i = 0, _len = paths.length; _i < _len; _i++) { + path = paths[_i]; + _results.push(this.addSound(path, first_stage)); + } + return _results; + }; + + ResourceManager.prototype.getImage = function(path) { + console.log("objs", this.resource_objects); + console.log("path", path); + return this.resource_objects.images[this.joinPath(path)]; + }; + + ResourceManager.prototype.prepare = function(finished_callback) { + if (finished_callback == null) { + finished_callback = (function() {}); + } + return pass; + }; + + ResourceManager.prototype.preload = function(progress_callback, finished_callback) { + var image, obj, _i, _len, _ref; + if (progress_callback == null) { + progress_callback = (function() {}); + } + if (finished_callback == null) { + finished_callback = (function() {}); + } + _ref = this.resources.images; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + image = _ref[_i]; + obj = document.createElement("img"); + obj.src = image; + this.resource_objects.images[image] = obj; + } + return finished_callback(); + }; + + return ResourceManager; + + })(); + + Scene = (function() { + function Scene(engine, name) { + this.engine = engine; + this.name = name; + this.changeScene = __bind(this.changeScene, this); + this.createInstance = __bind(this.createInstance, this); + this.checkMouseCollisions = __bind(this.checkMouseCollisions, this); + this.redraw = __bind(this.redraw, this); + this.iteration = __bind(this.iteration, this); + this.checkActive = __bind(this.checkActive, this); + this.removeTargetSurface = __bind(this.removeTargetSurface, this); + this.addTargetSurface = __bind(this.addTargetSurface, this); + this.instances = {}; + this.surfaces = []; + this.dirty = true; + this.last_instance_id = 100; + this.active = false; + this.width = 800; + this.height = 600; + this.last_width = 800; + this.last_height; + } + + Scene.prototype.addTargetSurface = function(surface) { + this.surfaces.push(surface); + this.engine.updateCanvasSize(surface, this.width, this.height); + $(surface).on("mousemove.radium", (function(_this) { + return function(event) { + var canvas_pos; + canvas_pos = surface.getBoundingClientRect(); + _this.mouse_x = Math.floor(event.clientX - canvas_pos.left); + _this.mouse_y = Math.floor(event.clientY - canvas_pos.top); + $("#debug").html("" + _this.mouse_x + " / " + _this.mouse_y); + return _this.checkMouseCollisions(); + }; + })(this)); + return this.checkActive(); + }; + + Scene.prototype.removeTargetSurface = function(surface) { + this.surfaces = this.surfaces.filter(function(obj) { + return obj !== surface; + }); + $(surface).off("mousemove.radium"); + return this.checkActive(); + }; + + Scene.prototype.checkActive = function() { + return this.active = this.surfaces.length > 0; + }; + + Scene.prototype.iteration = function() { + var id, instance, surface, _i, _len, _ref, _ref1, _ref2; + if (this.width !== this.last_width || this.height !== this.last_height) { + _ref = this.surfaces; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + surface = _ref[_i]; + this.engine.updateCanvasSize(surface, this.width, this.height); + } + _ref1 = [this.width, this.height], this.last_width = _ref1[0], this.last_height = _ref1[1]; + } + _ref2 = this.instances; + for (id in _ref2) { + instance = _ref2[id]; + if (instance.callEvent("step")) { + this.dirty = true; + } + } + if (this.dirty) { + this.redraw(); + return this.dirty = false; + } + }; + + Scene.prototype.redraw = function() { + var ctx, id, instance, surface, _i, _len, _ref, _results; + _ref = this.surfaces; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + surface = _ref[_i]; + ctx = this.engine.getSurface(surface); + ctx.clearRect(0, 0, surface.width, surface.height); + _results.push((function() { + var _ref1, _results1; + _ref1 = this.instances; + _results1 = []; + for (id in _ref1) { + instance = _ref1[id]; + _results1.push(instance.callEvent("draw", { + surface: surface + })); + } + return _results1; + }).call(this)); + } + return _results; + }; + + Scene.prototype.checkMouseCollisions = function() { + var id, instance, _ref, _results; + _ref = this.instances; + _results = []; + for (id in _ref) { + instance = _ref[id]; + if (instance.checkPointCollision(this.mouseX, this.mouseY)) { + _results.push(instance.callEvent("mouseover")); + } else { + _results.push(void 0); + } + } + return _results; + }; + + Scene.prototype.createInstance = function(object, x, y) { + var id, instance; + if (x == null) { + x = 0; + } + if (y == null) { + y = 0; + } + id = this.last_instance_id += 1; + instance = window.Object.create(this.engine.getObject(object)); + instance.x = x; + instance.y = y; + instance.id = id; + instance.scene = this; + this.instances[id] = instance; + instance.callEvent("create"); + return instance; + }; + + Scene.prototype.changeScene = function(scene) { + return pass; + }; + + return Scene; + + })(); + + Sound = (function() { + function Sound() {} + + return Sound; + + })(); + + Sprite = (function() { + function Sprite(engine, name, image) { + this.engine = engine; + this.name = name; + this.image = image; + this.getSize = __bind(this.getSize, this); + this.draw = __bind(this.draw, this); + pass; + } + + Sprite.prototype.draw = function(x, y, options, surface) { + var _ref; + if (options == null) { + options = {}; + } + if (surface == null) { + surface = ""; + } + surface = this.engine.getSurface(surface); + surface.globalAlpha = (_ref = options.alpha) != null ? _ref : 1; + return surface.drawImage(this.image, x, y); + }; + + Sprite.prototype.getSize = function() { + return { + width: this.image.width, + height: this.image.height + }; + }; + + return Sprite; + + })(); + + Tileset = (function() { + function Tileset(engine, name, image, tile_width, tile_height) { + this.engine = engine; + this.name = name; + this.image = image; + this.tile_width = tile_width; + this.tile_height = tile_height; + this.tile = __bind(this.tile, this); + this.tiles = {}; + } + + Tileset.prototype.tile = function(x, y, precise, w, h) { + var key, _ref; + if (precise == null) { + precise = false; + } + if (w == null) { + w = 0; + } + if (h == null) { + h = 0; + } + key = ("" + x + "/" + y + "/" + w + "/" + h + "/") + (precise ? 1 : 0); + return (_ref = this.tiles[key]) != null ? _ref : tiles[key] = new TilesetTile(this.engine, this, x, y, precise, w, h); + }; + + return Tileset; + + })(); + + TilesetTile = (function() { + function TilesetTile(engine, tileset, x, y, precise, w, h) { + this.engine = engine; + this.tileset = tileset; + this.x = x; + this.y = y; + this.precise = precise != null ? precise : false; + this.w = w != null ? w : 0; + this.h = h != null ? h : 0; + this.getSize = __bind(this.getSize, this); + this.draw = __bind(this.draw, this); + pass; + } + + TilesetTile.prototype.draw = function(x, y) { + var source_h, source_w, source_x, source_y, surface; + if (this.precise) { + source_x = this.x; + source_y = this.y; + source_w = this.w; + source_h = this.h; + } else { + source_x = this.x * this.tileset.tile_width; + source_y = this.y * this.tileset.tile_height; + source_w = this.tileset.tile_width; + source_h = this.tileset.tile_height; + } + surface = this.engine.getSurface(); + return surface.drawImage(source_x, source_y, source_width, source_height, x, y); + }; + + TilesetTile.prototype.getSize = function() { + if (this.precise) { + return { + width: this.w, + height: this.h + }; + } else { + return { + width: this.tileset.tile_width, + height: this.tileset.tile_height + }; + } + }; + + return TilesetTile; + + })(); + + util = { + stripRight: function(string, character) { + return string.replace(new RegExp(character + "*$", "g"), ""); + }, + unpackElement: function(element) { + console.log(element); + if (element instanceof jQuery) { + return element[0]; + } else { + return element; + } + } + }; + + window.ResourceManager = ResourceManager; + + window.Engine = Engine; + +}).call(this); diff --git a/gemswap.html b/gemswap.html new file mode 100644 index 0000000..925ef1a --- /dev/null +++ b/gemswap.html @@ -0,0 +1,14 @@ + + + + Gemswap + + + + + + + +
+ + \ No newline at end of file diff --git a/gemswap/assets/images/diamond.png b/gemswap/assets/images/diamond.png new file mode 100644 index 0000000..85d244a Binary files /dev/null and b/gemswap/assets/images/diamond.png differ diff --git a/gemswap/assets/images/diamond_inverted.png b/gemswap/assets/images/diamond_inverted.png new file mode 100644 index 0000000..f96a876 Binary files /dev/null and b/gemswap/assets/images/diamond_inverted.png differ diff --git a/gemswap/assets/images/diamond_shimmer.png b/gemswap/assets/images/diamond_shimmer.png new file mode 100644 index 0000000..90fbe9a Binary files /dev/null and b/gemswap/assets/images/diamond_shimmer.png differ diff --git a/gemswap/core.coffee b/gemswap/core.coffee new file mode 100644 index 0000000..672c23e --- /dev/null +++ b/gemswap/core.coffee @@ -0,0 +1,94 @@ +$(-> + manager = new ResourceManager("gemswap/assets") + engine = new Engine(manager) + + ### + # Configure pre-loading assets + manager.addImages([ + "images/loading_screen.png" + ], true) + ### + + # Configure game assets + manager.addImages([ + "images/diamond.png" + "images/diamond_inverted.png" + "images/diamond_shimmer.png" + ]) + + ### + manager.addSounds([ + "sfx/match.wav" + "sfx/swap.wav" + ]) + ### + + manager.prepare() + manager.preload(null, -> + engine.addCanvas($("#gamecanvas")); + + scene = engine.createScene("main") + + engine.createSprite("diamond", "images/diamond.png") + engine.createSprite("diamond_inverted", "images/diamond_inverted.png") + engine.createSprite("diamond_shimmer", "images/diamond_shimmer.png") + + diamond = engine.createObject("diamond") + diamond.sprite = engine.getSprite("diamond") + + diamond.onCreate = -> + @fade_step = 0.045 + @fade_current_step = @fade_step + @fade_value = 0 + @fade_decay_current = 9999 # Disable by default + @fade_decay_max = 8 + + @shimmer_step = 0.006 + @shimmer_current_step = @shimmer_step + @shimmer_value = 0 + + diamond.onStep = -> + if @fade_decay_current < Math.pow(2, @fade_decay_max) + @fade_value += @fade_current_step + + max = 1.5 / @fade_decay_current + + if @fade_value > Math.min(max, 1) + @fade_value = Math.min(max, 1) + @fade_current_step = -@fade_step + + if @fade_value <= 0 + @fade_value = 0 + @fade_decay_current *= 1.5 + @fade_current_step = @fade_step + + @shimmer_value += @shimmer_current_step + + if @shimmer_value > 0.7 + @shimmer_value = 0.7 + @shimmer_current_step = -@shimmer_step + + if @shimmer_value < 0 + @shimmer_value = 0 + @shimmer_current_step = @shimmer_step + + return true + + diamond.onDraw = -> + @engine.getSprite("diamond_inverted").draw(@x, @y, { + alpha: @fade_value + }) + + @engine.getSprite("diamond_shimmer").draw(@x - 14, @y - 14, { + alpha: @shimmer_value + }) + + diamond.onMouseOver = -> + console.log("mouseover") + @fade_decay_current = 1 + + scene.createInstance(diamond, 20, 20) + + engine.start() + ) +) \ No newline at end of file diff --git a/gemswap/gemswap.css b/gemswap/gemswap.css new file mode 100644 index 0000000..798b504 --- /dev/null +++ b/gemswap/gemswap.css @@ -0,0 +1,12 @@ +body +{ + text-align: center; + background-color: #000000; + color: white; +} + +#gamecanvas +{ + width: 800px; + height: 600px; +} \ No newline at end of file diff --git a/gemswap/gemswap.js b/gemswap/gemswap.js new file mode 100644 index 0000000..0bd32b2 --- /dev/null +++ b/gemswap/gemswap.js @@ -0,0 +1,85 @@ +// Generated by CoffeeScript 1.7.1 +(function() { + $(function() { + var engine, manager; + manager = new ResourceManager("gemswap/assets"); + engine = new Engine(manager); + + /* + * Configure pre-loading assets + manager.addImages([ + "images/loading_screen.png" + ], true) + */ + manager.addImages(["images/diamond.png", "images/diamond_inverted.png", "images/diamond_shimmer.png"]); + + /* + manager.addSounds([ + "sfx/match.wav" + "sfx/swap.wav" + ]) + */ + manager.prepare(); + return manager.preload(null, function() { + var diamond, scene; + engine.addCanvas($("#gamecanvas")); + scene = engine.createScene("main"); + engine.createSprite("diamond", "images/diamond.png"); + engine.createSprite("diamond_inverted", "images/diamond_inverted.png"); + engine.createSprite("diamond_shimmer", "images/diamond_shimmer.png"); + diamond = engine.createObject("diamond"); + diamond.sprite = engine.getSprite("diamond"); + diamond.onCreate = function() { + this.fade_step = 0.045; + this.fade_current_step = this.fade_step; + this.fade_value = 0; + this.fade_decay_current = 9999; + this.fade_decay_max = 8; + this.shimmer_step = 0.006; + this.shimmer_current_step = this.shimmer_step; + return this.shimmer_value = 0; + }; + diamond.onStep = function() { + var max; + if (this.fade_decay_current < Math.pow(2, this.fade_decay_max)) { + this.fade_value += this.fade_current_step; + max = 1.5 / this.fade_decay_current; + if (this.fade_value > Math.min(max, 1)) { + this.fade_value = Math.min(max, 1); + this.fade_current_step = -this.fade_step; + } + if (this.fade_value <= 0) { + this.fade_value = 0; + this.fade_decay_current *= 1.5; + this.fade_current_step = this.fade_step; + } + } + this.shimmer_value += this.shimmer_current_step; + if (this.shimmer_value > 0.7) { + this.shimmer_value = 0.7; + this.shimmer_current_step = -this.shimmer_step; + } + if (this.shimmer_value < 0) { + this.shimmer_value = 0; + this.shimmer_current_step = this.shimmer_step; + } + return true; + }; + diamond.onDraw = function() { + this.engine.getSprite("diamond_inverted").draw(this.x, this.y, { + alpha: this.fade_value + }); + return this.engine.getSprite("diamond_shimmer").draw(this.x - 14, this.y - 14, { + alpha: this.shimmer_value + }); + }; + diamond.onMouseOver = function() { + console.log("mouseover"); + return this.fade_decay_current = 1; + }; + scene.createInstance(diamond, 20, 20); + return engine.start(); + }); + }); + +}).call(this); diff --git a/gemswap/source/diamond.svg b/gemswap/source/diamond.svg new file mode 100644 index 0000000..7b2721f --- /dev/null +++ b/gemswap/source/diamond.svg @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gemswap/source/diamond_inverted.svg b/gemswap/source/diamond_inverted.svg new file mode 100644 index 0000000..9d705c1 --- /dev/null +++ b/gemswap/source/diamond_inverted.svg @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gemswap/source/diamond_shimmer.svg b/gemswap/source/diamond_shimmer.svg new file mode 100644 index 0000000..1b8a25f --- /dev/null +++ b/gemswap/source/diamond_shimmer.svg @@ -0,0 +1,347 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/radium/000_prepare.coffee b/radium/000_prepare.coffee new file mode 100644 index 0000000..e69de29 diff --git a/radium/base.coffee b/radium/base.coffee new file mode 100644 index 0000000..e69de29 diff --git a/radium/engine.coffee b/radium/engine.coffee new file mode 100644 index 0000000..025717a --- /dev/null +++ b/radium/engine.coffee @@ -0,0 +1,106 @@ +window.pass = undefined # This will give us Python-like noop calls + +class Engine + constructor: (@resource_manager) -> + @canvases = {} + @fps = 45 + @last_frameskip_collection = Math.floor(Date.now()) + @frameskip = 0 + @current_frameskip = 0 + + @scenes = {} + @objects = {} + @sounds = {} + @sprites = {} + @tilesets = {} + + addCanvas: (canvas, label = "") => + @canvases[label] = util.unpackElement(canvas) + + createSurface: (label) => + @canvases[label] = document.createElement("canvas") + + getSurface: (label) => + if typeof label == "string" + return @canvases[label]?.getContext("2d") + else if label.tagName == "CANVAS" + return label.getContext("2d") + else + return label + + updateCanvasSize: (canvas, w, h) => + canvas.width = w + canvas.height = h + canvas.style.width = "#{w}px" + canvas.style.height = "#{h}px" + + start: () => + @initial_scene.addTargetSurface(@canvases[""]) + @loop() + + loop: () => + @iteration() + + iteration: () => + # Calculation of next frame and frameskip collection check + frame_interval = (1000 / @fps) + + current_frame = Date.now() + next_frame = current_frame + frame_interval + + if Math.floor(current_frame) > @last_frameskip_collection + @frameskip = @current_frameskip + @current_frameskip = 0 + @last_frameskip_collection = Math.floor(current_frame) + + # Actual iteration code + scene.iteration() for name, scene of @scenes when scene.active + + # Frameskip check and triggering next iteration + if Date.now() < next_frame + setTimeout(@iteration, (next_frame - Date.now())) + else + # Frameskip! + overtime = Date.now() - next_frame + @current_frameskip += Math.floor(overtime / frame_interval) + belated_timeout = overtime % frame_interval + setTimeout(@iteration, belated_timeout) + + setInitialScene: (scene) => + @initial_scene = scene + + setPreloadScene: (scene) => + @preload_scene = scene + + createScene: (name) => + scene = new Scene(this, name) + @initial_scene ?= scene + @scenes[name] = scene + + createObject: (name) => + @objects[name] = new Object(this, name) + + createSound: (name, sound) => + @sounds[name] = new Sound(this, name, @resource_manager.getSound(sound)) + + createSprite: (name, image) => + console.log("gget", @resource_manager.getImage(image)) + @sprites[name] = new Sprite(this, name, @resource_manager.getImage(image)) + + createTileset: (name, image, tile_width, tile_height) => + @tilesets[name] = new Tileset(this, name, @resource_manager.getImage(image), tile_width, tile_height) + + getScene: (name) => + if typeof name == "string" then @scenes[name] else name + + getObject: (name) => + if typeof name == "string" then @objects[name] else name + + getSound: (name) => + if typeof name == "string" then @sounds[name] else name + + getSprite: (name) => + if typeof name == "string" then @sprites[name] else name + + getTileset: (name) => + if typeof name == "string" then @tilesets[name] else name \ No newline at end of file diff --git a/radium/engine.draw.coffee b/radium/engine.draw.coffee new file mode 100644 index 0000000..0f2a400 --- /dev/null +++ b/radium/engine.draw.coffee @@ -0,0 +1,113 @@ +Engine::draw = + _startPath: (surface, options) => + surface = @getSurface(surface) + + if not options._is_text ? false + surface.beginPath() + + return surface + + _finishPath: (surface, options) => + if options.stroke ? true + surface.lineWidth = options.lineWidth ? options.pen?.lineWidth ? 1 + surface.strokeStyle = options.lineColor ? options.pen?.lineColor ? "black" + + if options._is_text ? false + surface.strokeText(options.text, options.x, options.y) + else + surface.stroke() + + if options.fill ? false + surface.fillStyle = options.fillColor ? options.pen?.fillColor ? "white" + + if options._is_text ? false + surface.fillText(options.text, options.x, options.y) + else + surface.fill() + + _getTextWidth: (surface, text, options) => + @_applyTextContext(surface, options) + width = surface.measureText(text).width + surface.restore() + return width + + _applyTextContext: (surface, options) => + font_family = options.font ? "sans-serif" + font_size = options.size ? 16 + font_weight = options.weight ? "normal" + font_style = options.style ? "normal" + scale = options.scale ? 1 + + surface.save() + surface.font = "#{font_weight} #{font_style} #{font_size}px '#{font_family}'" + surface.globalAlpha = options.alpha ? 1 + surface.scale(scale, scale) + + line: (x1, y1, x2, y2, options = {}, surface = "") => + surface = @_startPath(surface, options) + surface.moveTo(x1, y1) + surface.lineTo(x2, y2) + @_finishPath(surface, options) + + rectangle: (x1, y1, x2, y2, options = {}, surface = "") => + surface = @_startPath(surface, options) + surface.rect(x1, y1, x2 - x1, y2 - y1) + @_finishPath(surface, options) + + boxEllipse: (x1, y1, x2, y2, options = {}, surface = "") => + x = (x1 + x2) / 2; + y = (y1 + y2) / 2; + rx = (x2 - x1) / 2; + ry = (y2 - y1) / 2; + @radiusEllipse(x, y, rx, ry, options, surface) + + radiusEllipse: (x, y, rx, ry, options = {}, surface = "") => + surface = @_startPath(surface, options) + + step = options.step ? 0.1 + + if rx == ry + surface.arc(x, y, rx, 0, 2 * Math.PI, false) + else + surface.moveTo(x + rx, y) + + for i in [0 .. (Math.PI * 2 + step)] + surface.lineTo(x + (Math.cos(i) * rx), y + (Math.sin(i) * ry)) + + @_finishPath(surface, options) + + boxPolygon: (x1, y1, x2, y2, sides, options = {}, surface = "") => + pass # TODO + + radiusPolygon: (x, y, r, sides, options = {}, surface = "") => + pass # TODO + + text: (x, y, text, options = {}, surface = "") => + # Defaults + options.alignment ?= "left" + options.scale ?= 1 + options._is_text = true + options.text = text + options.y = y + + # Text needs different default color settings from other shapes... + options.fill ?= true + options.fillColor ?= "black" + options.stroke ?= false + + # X coordinate will be calculated depending on alignment + if alignment == "left" + options.x = x + else + text_width = @_getTextWidth(text, options) + + if alignment == "center" + options.x = x - ((text_width / 2) * scale * scale) + else if alignment == "right" + options.x = x - text_width # FIXME: Possibly broken wrt scale? + + @_startPath(surface, options) + @_finishPath(surface, options) + + # This is to avoid scale from affecting anything else + surface.restore() \ No newline at end of file diff --git a/radium/engine.random.coffee b/radium/engine.random.coffee new file mode 100644 index 0000000..dd13486 --- /dev/null +++ b/radium/engine.random.coffee @@ -0,0 +1,13 @@ +Engine::random = + number: (min, max, precision) => + base_number = Math.random() + space = Math.abs(ceiling - floor) + rounding_factor = 1 / (precision ? 0.00000001) + return Math.floor((min + (base_number * space)) * rounding_factor) / rounding_factor + + pick: (options...) => + return options[Math.floor(Math.random() * options.length)] + + string: (length, alphabet) => + alphabet ?= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + return (alphabet[Math.floor(Math.random() * alphabet.length)] for i in [0 .. length - 1]).join("") \ No newline at end of file diff --git a/radium/object.coffee b/radium/object.coffee new file mode 100644 index 0000000..95ef082 --- /dev/null +++ b/radium/object.coffee @@ -0,0 +1,35 @@ +class Object + constructor: (@engine, @name) -> + @sprite = null + @x = 0 + @y = 0 + + callEvent: (name, data = {}) => + switch name + when "create" then @onCreate?(data) + when "step" then @onStep?(data) + when "draw" + @drawSelf(data.surface ? "") + @onDraw?(data) + + drawSelf: (surface) => + @drawSprite(surface) + + drawSprite: (surface = "") => + @sprite.draw(@x, @y, {}, surface) if @sprite? and (@draw_sprite ? "true") + + getBoundingBox: => + image_size = @sprite?.getSize() + + return { + x1: @x + x2: @x + image_size?.width + y1: @y + y2: @y + image_size?.height + } + + checkPointCollision: (x, y) => + # TODO: Precision collision matching! + bounding_box = @getBoundingBox() + + return x >= bounding_box?.x1 and x <= bounding_box?.x2 and y >= bounding_box?.y1 and y <= bounding_box?.y2 diff --git a/radium/resource-manager.coffee b/radium/resource-manager.coffee new file mode 100644 index 0000000..ebe90a7 --- /dev/null +++ b/radium/resource-manager.coffee @@ -0,0 +1,63 @@ +class ResourceManager + constructor: (@base_path = "") -> + @resources = + stage1_images: [] + stage1_audio: [] + stage1_scripts: [] + images: [] + audio: [] + scripts: [] + + @resource_objects = + images: {} + audio: {} + scripts: {} + + joinPath: (path) => + if @base_path == "" then path else util.stripRight(@base_path, "/") + "/" + path + + addImage: (path, first_stage = false) => + if first_stage + @resources.stage1_images.push(@joinPath(path)) + else + @resources.images.push(@joinPath(path)) + + addSound: (path, first_stage = false) => + if first_stage + @resources.stage1_audio.push(@joinPath(path)) + else + @resources.audio.push(@joinPath(path)) + + addScript: (path, first_stage = false) => + if first_stage + @resources.stage1_scripts.push(@joinPath(path)) + else + @resources.scripts.push(@joinPath(path)) + + addImages: (paths, first_stage = false) => + @addImage(path, first_stage) for path in paths + + addScripts: (paths, first_stage = false) => + @addScript(path, first_stage) for path in paths + + addSounds: (paths, first_stage = false) => + @addSound(path, first_stage) for path in paths + + getImage: (path) => + # FIXME: Do properly when PreloadJS is added + console.log("objs", @resource_objects) + console.log("path", path) + return @resource_objects.images[@joinPath(path)] + + prepare: (finished_callback = (->)) => + # This performs a stage 1 preload, loading the initial assets required for displaying the preload screen. + pass + + preload: (progress_callback = (->), finished_callback = (->)) => + # This performs the stage 2 preload; it will load the actual game assets. + for image in @resources.images + obj = document.createElement("img") + obj.src = image + @resource_objects.images[image] = obj + + finished_callback() \ No newline at end of file diff --git a/radium/scene.coffee b/radium/scene.coffee new file mode 100644 index 0000000..93972b7 --- /dev/null +++ b/radium/scene.coffee @@ -0,0 +1,72 @@ +class Scene + constructor: (@engine, @name) -> + @instances = {} + @surfaces = [] + @dirty = true # Triggers first draw + @last_instance_id = 100 + @active = false + @width = 800 + @height = 600 + @last_width = 800 + @last_height + + addTargetSurface: (surface) => + @surfaces.push(surface) + @engine.updateCanvasSize(surface, @width, @height) + $(surface).on("mousemove.radium", (event) => + canvas_pos = surface.getBoundingClientRect() + @mouse_x = Math.floor(event.clientX - canvas_pos.left) + @mouse_y = Math.floor(event.clientY - canvas_pos.top) + $("#debug").html("#{@mouse_x} / #{@mouse_y}") + @checkMouseCollisions() + ) + @checkActive() + + removeTargetSurface: (surface) => + @surfaces = @surfaces.filter (obj) -> obj isnt surface + $(surface).off("mousemove.radium") + @checkActive() + + checkActive: => + @active = (@surfaces.length > 0) + + iteration: => + if @width != @last_width or @height != @last_height + @engine.updateCanvasSize(surface, @width, @height) for surface in @surfaces + [@last_width, @last_height] = [@width, @height] + + for id, instance of @instances + if instance.callEvent("step") + @dirty = true + + if @dirty + @redraw() + @dirty = false + + redraw: => + for surface in @surfaces + ctx = @engine.getSurface(surface) + ctx.clearRect(0, 0, surface.width, surface.height); + instance.callEvent("draw", {surface: surface}) for id, instance of @instances + + checkMouseCollisions: => + for id, instance of @instances + instance.callEvent("mouseover") if instance.checkPointCollision(@mouseX, @mouseY) + + createInstance: (object, x = 0, y = 0) => + id = @last_instance_id += 1 + + instance = window.Object.create(@engine.getObject(object)) + instance.x = x + instance.y = y + instance.id = id + instance.scene = this + @instances[id] = instance + + instance.callEvent("create") + + return instance + + changeScene: (scene) => + # This will change to a different scene, but inherit the target surfaces + pass \ No newline at end of file diff --git a/radium/sound.coffee b/radium/sound.coffee new file mode 100644 index 0000000..e413191 --- /dev/null +++ b/radium/sound.coffee @@ -0,0 +1 @@ +class Sound \ No newline at end of file diff --git a/radium/sprite.coffee b/radium/sprite.coffee new file mode 100644 index 0000000..389d0ee --- /dev/null +++ b/radium/sprite.coffee @@ -0,0 +1,12 @@ +class Sprite + constructor: (@engine, @name, @image) -> + pass + + draw: (x, y, options = {}, surface = "") => + surface = @engine.getSurface(surface) + # TODO: Options. + surface.globalAlpha = options.alpha ? 1 + surface.drawImage(@image, x, y) + + getSize: => + return {width: @image.width, height: @image.height} \ No newline at end of file diff --git a/radium/tileset.coffee b/radium/tileset.coffee new file mode 100644 index 0000000..911149c --- /dev/null +++ b/radium/tileset.coffee @@ -0,0 +1,30 @@ +class Tileset + constructor: (@engine, @name, @image, @tile_width, @tile_height) -> + @tiles = {} + + tile: (x, y, precise = false, w = 0, h = 0) => + key = "#{x}/#{y}/#{w}/#{h}/" + if precise then 1 else 0 + @tiles[key] ? tiles[key] = new TilesetTile(@engine, this, x, y, precise, w, h) + +class TilesetTile + constructor: (@engine, @tileset, @x, @y, @precise = false, @w = 0, @h = 0) -> + pass + + draw: (x, y) => + if @precise + source_x = @x + source_y = @y + source_w = @w + source_h = @h + else + source_x = @x * @tileset.tile_width + source_y = @y * @tileset.tile_height + source_w = @tileset.tile_width + source_h = @tileset.tile_height + + surface = @engine.getSurface() + # TODO: Options. + surface.drawImage(source_x, source_y, source_width, source_height, x, y) + + getSize: => + return if @precise then {width: @w, height: @h} else {width: @tileset.tile_width, height: @tileset.tile_height} \ No newline at end of file diff --git a/radium/util.coffee b/radium/util.coffee new file mode 100644 index 0000000..119267b --- /dev/null +++ b/radium/util.coffee @@ -0,0 +1,6 @@ +util = + stripRight: (string, character) -> + string.replace(new RegExp(character + "*$", "g"), "") + unpackElement: (element) -> + console.log(element) + if element instanceof jQuery then element[0] else element \ No newline at end of file diff --git a/radium/zzz_exports.coffee b/radium/zzz_exports.coffee new file mode 100644 index 0000000..87c171d --- /dev/null +++ b/radium/zzz_exports.coffee @@ -0,0 +1,2 @@ +window.ResourceManager = ResourceManager +window.Engine = Engine \ No newline at end of file diff --git a/watch.sh b/watch.sh new file mode 100755 index 0000000..a0a3680 --- /dev/null +++ b/watch.sh @@ -0,0 +1,3 @@ +#!/bin/bash +coffee -w -c -j gemswap.coffee -o gemswap/ gemswap/*.coffee& +coffee -w -c -j radium.coffee -o compiled/ radium/*.coffee