require("./../rur.js"); require("./../utils/validator.js"); var record_id = require("./../../lang/msg.js").record_id; record_id("robot0"); record_id("robot1"); record_id("robot2"); record_id("robot3"); RUR.vis_robot = {}; RUR.vis_robot.images = {}; // we will keep track if we have loaded all images RUR.vis_robot.loaded_images = 0; RUR.vis_robot.nb_images = 0; // enable changing defaults for unit tests or if put on different server location RUR.BASE_URL = RUR.BASE_URL || ''; function set_images(images) { "use strict" var default_images, east, west, north, south, robot, model = images.model; default_images = {east: RUR.BASE_URL + '/src/images/robot_e.png', north: RUR.BASE_URL + '/src/images/robot_n.png', west: RUR.BASE_URL + '/src/images/robot_w.png', south: RUR.BASE_URL + '/src/images/robot_s.png' } if (RUR.KNOWN_ROBOT_MODELS.indexOf(model) == -1) { RUR.KNOWN_ROBOT_MODELS.push(model); } if (RUR.vis_robot.images[model] === undefined) { RUR.vis_robot.images[model] = {}; robot = RUR.vis_robot.images[model]; robot.robot_e_img = new Image(); robot.robot_n_img = new Image(); robot.robot_w_img = new Image(); robot.robot_s_img = new Image(); } else { robot = RUR.vis_robot.images[model]; } if (robot.robot_e_img.src != images.east) { robot.robot_e_img.src = images.east || default_images.east; robot.e_url = images.east || '/src/images/robot_e.png'; robot.robot_e_img.onload = RUR.onload_new_image; RUR.state.reset_default_robot_images_needed = true; } if (robot.robot_n_img.src != images.north) { robot.robot_n_img.src = images.north || default_images.north; robot.n_url = images.north || '/src/images/robot_n.png'; robot.robot_n_img.onload = RUR.onload_new_image; RUR.state.reset_default_robot_images_needed = true; } if (robot.robot_w_img.src != images.west) { robot.robot_w_img.src = images.west || default_images.west; robot.w_url = images.west || '/src/images/robot_w.png'; robot.robot_w_img.onload = RUR.onload_new_image; RUR.state.reset_default_robot_images_needed = true; } if (robot.robot_s_img.src != images.south) { robot.robot_s_img.src = images.south || default_images.south; robot.s_url = images.south || '/src/images/robot_s.png'; robot.robot_s_img.onload = RUR.onload_new_image; RUR.state.reset_default_robot_images_needed = true; } } RUR.reset_default_robot_images = function () { "use strict" var saved_model; set_images({model: "classic"}); // classic; uses default set_images({model: "2d red rover", east: RUR.BASE_URL + '/src/images/rover_e.png', north: RUR.BASE_URL + '/src/images/rover_n.png', west: RUR.BASE_URL + '/src/images/rover_w.png', south: RUR.BASE_URL + '/src/images/rover_s.png' }); set_images({model: "3d red rover", east: RUR.BASE_URL + '/src/images/plain_e.png', north: RUR.BASE_URL + '/src/images/plain_n.png', west: RUR.BASE_URL + '/src/images/plain_w.png', south: RUR.BASE_URL + '/src/images/plain_s.png' }); set_images({model: "solar panel", east: RUR.BASE_URL + '/src/images/sp_e.png', north: RUR.BASE_URL + '/src/images/sp_n.png', west: RUR.BASE_URL + '/src/images/sp_w.png', south: RUR.BASE_URL + '/src/images/sp_s.png' }); $("#robot0 img").attr("src", RUR.vis_robot.images["classic"].robot_e_img.src); $("#robot1 img").attr("src", RUR.vis_robot.images["2d red rover"].robot_e_img.src); $("#robot2 img").attr("src", RUR.vis_robot.images["3d red rover"].robot_e_img.src); $("#robot3 img").attr("src", RUR.vis_robot.images["solar panel"].robot_e_img.src); // handle situation where the user had saved values from old naming styles saved_model = localStorage.getItem("robot_default_model"); if (saved_model==0 || saved_model==1 || saved_model==2 || saved_model==3) { saved_model = RUR.reeborg_default_model; localStorage.setItem("robot_default_model", saved_model); } RUR.user_selected_model = saved_model; RUR.select_default_robot_model(saved_model); // additional robot images from rur-ple set_images({model: "blue", east: RUR.BASE_URL + '/src/images/blue_robot_e.png', north: RUR.BASE_URL + '/src/images/blue_robot_n.png', west: RUR.BASE_URL + '/src/images/blue_robot_w.png', south: RUR.BASE_URL + '/src/images/blue_robot_s.png' }); set_images({model: "purple", east: RUR.BASE_URL + '/src/images/purple_robot_e.png', north: RUR.BASE_URL + '/src/images/purple_robot_n.png', west: RUR.BASE_URL + '/src/images/purple_robot_w.png', south: RUR.BASE_URL + '/src/images/purple_robot_s.png' }); set_images({model: "green", east: RUR.BASE_URL + '/src/images/green_robot_e.png', north: RUR.BASE_URL + '/src/images/green_robot_n.png', west: RUR.BASE_URL + '/src/images/green_robot_w.png', south: RUR.BASE_URL + '/src/images/green_robot_s.png' }); set_images({model: "light blue", east: RUR.BASE_URL + '/src/images/light_blue_robot_e.png', north: RUR.BASE_URL + '/src/images/light_blue_robot_n.png', west: RUR.BASE_URL + '/src/images/light_blue_robot_w.png', south: RUR.BASE_URL + '/src/images/light_blue_robot_s.png' }); set_images({model: "yellow", east: RUR.BASE_URL + '/src/images/yellow_robot_e.png', north: RUR.BASE_URL + '/src/images/yellow_robot_n.png', west: RUR.BASE_URL + '/src/images/yellow_robot_w.png', south: RUR.BASE_URL + '/src/images/yellow_robot_s.png' }); RUR.state.reset_default_robot_images_needed = false; }; RUR.select_default_robot_model = function (model) { "use strict"; var robot; if ( !(model == "classic" || model == "2d red rover" || model == "3d red rover" || model == "solar panel")){ model = RUR.reeborg_default_model; } // the user could click on the robot model buttons when there are // no robot present in the world. try { robot = RUR.get_current_world().robots[0]; robot.model = model; RUR.user_selected_model = model; } catch (e) {} RUR.vis_robot.e_img = RUR.vis_robot.images[model].robot_e_img; RUR.vis_robot.n_img = RUR.vis_robot.images[model].robot_n_img; RUR.vis_robot.w_img = RUR.vis_robot.images[model].robot_w_img; RUR.vis_robot.s_img = RUR.vis_robot.images[model].robot_s_img; if (RUR.vis_world !== undefined) { RUR.vis_world.refresh(); } localStorage.setItem("robot_default_model", model); }; $("#robot0").on("click", function (evt) { RUR.select_default_robot_model("classic"); }); $("#robot1").on("click", function (evt) { RUR.select_default_robot_model("2d red rover"); }); $("#robot2").on("click", function (evt) { RUR.select_default_robot_model("3d red rover"); }); $("#robot3").on("click", function (evt) { RUR.select_default_robot_model("solar panel"); }); RUR.reset_default_robot_images(); // the following is to try to ensure that the images are loaded before the "final" // original drawing is made RUR.vis_robot.e_img.onload = function () { RUR.vis_robot.loaded_images += 1; }; RUR.vis_robot.nb_images += 1; RUR.vis_robot.w_img.onload = function () { RUR.vis_robot.loaded_images += 1; }; RUR.vis_robot.nb_images += 1; RUR.vis_robot.n_img.onload = function () { RUR.vis_robot.loaded_images += 1; }; RUR.vis_robot.nb_images += 1; RUR.vis_robot.s_img.onload = function () { RUR.vis_robot.loaded_images += 1; }; RUR.vis_robot.nb_images += 1; /**@function animate_robot * @memberof RUR * @instance * * @desc Robot animation is done by cycling through a list of robot models, * each model having 4 images (one for each orientation). * * @param {array} models A list of robot models. If the list contains a single * model, the animation is stopped. * @param {object} robot_body A robot_body object. */ RUR.animate_robot = function (models, robot_body) { "use strict" if (robot_body === undefined) { robot_body = RUR.get_current_world().robots[0]; } if (models.length > 1) { robot_body.models_cycle = models; robot_body.model_index = 0; } else { robot_body.models_cycle = null; robot_body.model = models[0]; } RUR.record_frame("animate robot", robot_body.__id); RUR.state.animated_robots = true; }; function update_model(robot) { // robot == robot.body var default_robot, nb_models = robot.models_cycle.length; if (robot.model_index == undefined) { robot.model_index = 0; } robot.model = robot.models_cycle[robot.model_index]; default_robot = RUR.get_current_world().robots[0]; if (default_robot.__id == robot.__id) { RUR.user_selected_model = undefined; // overrides the user's choice } // do we cycle through the value; a model number of -1 ends a cycle if (robot.model_index == nb_models-2){ if (robot.models_cycle[robot.model_index+1] == -1){ return; } } robot.model_index += 1; robot.model_index %= nb_models; return; }; RUR.vis_robot.draw = function (robot) { "use strict"; var x, y, width, height, image, default_robot; if (!robot) { console.warn("RUR.vis_robot.draw called with no robot."); return; } // handling legacy Code if (robot.orientation !== undefined) { robot._orientation = robot.orientation; robot.orientation = null; } if (robot.x > RUR.MAX_X || robot.y > RUR.MAX_Y) { return; } // all images are taken to be centered on a tile 40x40, which are scaled // appropriately width = RUR.TILE_SIZE * RUR.SCALE; height = RUR.TILE_SIZE * RUR.SCALE; x = robot.x*RUR.WALL_LENGTH + RUR.WALL_THICKNESS/2; y = RUR.HEIGHT - (robot.y+1)*RUR.WALL_LENGTH + RUR.WALL_THICKNESS/2; if (robot.models_cycle) { update_model(robot); } if (robot.model == undefined) { robot.model = RUR.reeborg_default_model; } else if (RUR.KNOWN_ROBOT_MODELS.indexOf(robot.model) == -1) { console.warn("robot model not defined: " + robot.model); robot.model = RUR.reeborg_default_model; } if (RUR.user_selected_model !== undefined) { default_robot = RUR.get_current_world().robots[0]; if (default_robot.__id == robot.__id ) { robot.model = RUR.user_selected_model; } } switch(robot._orientation){ case RUR.EAST: image = RUR.vis_robot.images[robot.model].robot_e_img; break; case RUR.NORTH: image = RUR.vis_robot.images[robot.model].robot_n_img; break; case RUR.WEST: image = RUR.vis_robot.images[robot.model].robot_w_img; break; case RUR.SOUTH: image = RUR.vis_robot.images[robot.model].robot_s_img; break; case -1: RUR.vis_robot.draw_random(robot); default: image = RUR.vis_robot.e_img; } RUR.ROBOT_CTX.drawImage(image, x, y, width, height); if (RUR.state.editing_world){ return; } RUR.vis_robot.draw_trace_history(robot); }; // drawing random orientation robot RUR.vis_robot.draw_random = function (robot) { "use strict"; var x, y, width, height, image, random_orientation; if (!robot) { console.warn("RUR.vis_robot.draw_random called with no robot."); return; } if (!(robot._orientation == -1 || robot.orientation == -1)) { console.warn("RUR.vis_robot.draw_random but orientation != -1."); return; } if (robot.x > RUR.MAX_X || robot.y > RUR.MAX_Y) { return; } // all images are taken to be centered on a tile 40x40, which are scaled // appropriately width = RUR.TILE_SIZE * RUR.SCALE; height = RUR.TILE_SIZE * RUR.SCALE; x = robot.x*RUR.WALL_LENGTH + RUR.WALL_THICKNESS/2; y = RUR.HEIGHT - (robot.y+1)*RUR.WALL_LENGTH + RUR.WALL_THICKNESS/2; random_orientation = Math.floor(Math.random() * 4) switch(random_orientation){ case RUR.EAST: if (robot.model !== undefined){ image = RUR.vis_robot.images[robot.model].robot_e_img; } else { image = RUR.vis_robot.e_img; } break; case RUR.NORTH: if (robot.model !== undefined){ image = RUR.vis_robot.images[robot.model].robot_n_img; } else { image = RUR.vis_robot.n_img; } break; case RUR.WEST: if (robot.model !== undefined){ image = RUR.vis_robot.images[robot.model].robot_w_img; } else { image = RUR.vis_robot.w_img; } break; case RUR.SOUTH: if (robot.model !== undefined){ image = RUR.vis_robot.images[robot.model].robot_s_img; } else { image = RUR.vis_robot.s_img; } break; default: image = RUR.vis_robot.e_img; console.warn("default should not happen in RUR.vis_robot.draw_random."); } RUR.ROBOT_ANIM_CTX.drawImage(image, x, y, width, height); RUR.state.random_robot = true; }; RUR.vis_robot.draw_trace_history = function(robot) { var segment; for (segment of robot._trace_history) { //jshint ignore:line RUR.vis_robot.draw_trace_segment(segment); } }; RUR.vis_robot.draw_trace_segment = function (segment) { "use strict"; var ctx = RUR.TRACE_CTX; ctx.strokeStyle = segment["color"]; ctx.lineWidth = segment["thickness"]; ctx.lineCap = "round"; ctx.beginPath(); ctx.moveTo(segment["prev_x"], segment["prev_y"]); ctx.lineTo(segment["x"], segment["y"]); ctx.stroke(); }; /** @function new_robot_images * @memberof RUR * @instance * * @desc Create new images for the robot. * * **Suggestion**: use in the Onload editor, so that images can be fetched * as soon as the world is loaded. * * **Python**: You _can_ use `new_robot_images` without the `RUR` prefix. For the * French version, you can use `nouvelles_images_de_robot`. However, the * function described here is preferable as it can be used with either * Javascript or Python. * * @param {Object} images A Javascript object (similar to a Python dict) that * holds the relevant attributes. * * @param {string} [images.model] The model name of the robot. Integer values * will be accepted as well except for -1 which will raise an error. If the * model is not specified, the value `"anonymous"` will be used. * * @param {string} [images.east] A url for the source of the image to be used * for the robot in the East orientation. If it is not specified, the * default "classic" image will be used. * * @param {string} [images.north] Similar to `images.east`. * @param {string} [images.west] Similar to `images.east`. * @param {string} [images.south] Similar to `images.east`. * */ RUR.new_robot_images = function (images) { var model, random; if (images.model !== undefined) { if (images.model == -1) { throw new RUR.ReeborgError(RUR.translate("Robot model cannot be -1.")); } model = images.model; } else { images.model = model = "anonymous"; } set_images(images); }; /** @function show_all_robots * @memberof RUR * @instance * * @summary This method shows all known robot models in a table. * */ RUR.show_all_robots = function () { var info, model, east, north, west, south, e_url, w_url, s_url, n_url; info = "<table border='1'><tr><th>model</th><th>east</th><th>north</th><th>west</th><th>south</th></tr>"; for (model in RUR.vis_robot.images) { if (RUR.vis_robot.images.hasOwnProperty(model)) { east = RUR.vis_robot.images[model].robot_e_img.src; north = RUR.vis_robot.images[model].robot_n_img.src; west = RUR.vis_robot.images[model].robot_w_img.src; south = RUR.vis_robot.images[model].robot_s_img.src; e_url = RUR.vis_robot.images[model].e_url; n_url = RUR.vis_robot.images[model].n_url; w_url = RUR.vis_robot.images[model].w_url; s_url = RUR.vis_robot.images[model].s_url; info += "<tr><td>" + model + "</td>"; info += "<td><img src = '" + east + "'><br>" + e_url + "</td>"; info += "<td><img src = '" + north + "'><br>" + n_url + "</td>"; info += "<td><img src = '" + west + "'><br>" + w_url + "</td>"; info += "<td><img src = '" + south + "'><br>" + s_url + "</td></tr>"; } } info += "</table>"; RUR._print_html_(info, true); // true will replace existing content return null; // for the python repl };