Two.JS rendering from different scopes - javascript

I'm building a desktop application using Electron and Two.js. The application is basically a 2D level editor. There are Tile objects which represent 32x32 tiles in game. There's an array of Tile objects and I have tried to draw them using Two.JS but as it turns out twois not able to find renderable stuff which are not in the same scope as two.update()
I have tried creating a group using two.makeGroup() and then while looping Tile objects, i've tried adding them to the group using two.add(newRect). No luck.
Doing it this way doesn't work at all. (out of scope?)
for (let i = 0; i < tiles.length-1; i++) {
let rect = two.makeRectangle(tiles[i].getX(), tiles[i].getY(), size, size);
rect.fill = 'rgb('+tiles[i].color[0]+', '+tiles[i].color[1]+', '+tiles[i].color[2]+')';
rect.noStroke();
}
two.update();
but this way works quite fine for some reason
let rect = two.makeRectangle(tiles[i].getX(), tiles[i].getY(), size, size);
rect.fill = 'rgb('+tiles[i].color[0]+', '+tiles[i].color[1]+', '+tiles[i].color[2]+')';
rect.noStroke();
two.update();
My question is: How do I render multiple objects from different scopes?
(where it doesn't draw) this function is where im trying to draw from : https://github.com/idontreallywolf/gyarb_mapper/blob/750eddc6cbb179d359c47b4fc6711c9e79a0472d/renderer.js#L73
EDIT : (where it is able to draw)
I tried adding a random function, it worked with this one. For some reason the previous scope is not (detected?)
function troll(){
let rect = two.makeRectangle(100, 100, 100, 100);
rect.fill = "rgb(255,255,255)";
rect.stroke = "#f00";
}
troll();
two.update();
UPDATE:
Two.js wasn't able to draw them because the variables that I've used as parameters were inaccessible in that scope, so after doing some debugging I've solved the issue.

Related

How to draw rectangles inside a polygon using p5.js

I am working on a project for a solar panel installation calculator on roofs. The solar panels are rectangular and have fixed widths and heights. But the roofs are dynamic in shape, i.e. a polygon with multiple sides. See the attached image for reference.
I am trying to find out the maximum number of panels that can be installed on the roofs. I need to place the rectangles (panels) inside the polygon (roof), which you can not overlap and can not touch the boundary.
I was trying to achieve this using p5.js.
Here are the basic codes.
function setup() {
createCanvas(800, 500);
background(220);
noLoop();
}
function draw() {
fill(237, 34, 93);
beginShape();
vertex(50, 50);
vertex(750, 50);
vertex(750, 450);
vertex(500, 450);
vertex(500, 200);
vertex(350, 200);
vertex(350, 450);
vertex(50, 450);
endShape(CLOSE);
var solarPanel = {
width: 40,
height: 40
};
//Algorithm to add the solar panels.
}
Link to p5.js editor - https://editor.p5js.org/abhishekdas/sketches/cVoxihH0n
I am new to p5.js. Can anyone please help me to find the correct Algorithm?
One simple option is to lay the panels in a grid. Your typical nested for loop should do the trick: remember to add the spacing required between panels when computing the position of each one (this should take care of overlaps).
Regarding panels laying inside the polygon of the shape you can get started with this point in polygon p5.js example. If you can test one point, you can check 4 points. If you can check 4 points (1 panel), you can check all panels) then simply remove the ones that aren't inside the roof polygon from the grid.
For reference here's function:
function pointInPoly(verts, pt) {
let c = false;
for (let i = 0, j = verts.length - 1; i < verts.length; j = i++) {
if (((verts[i].y > pt.y) != (verts[j].y > pt.y)) && (pt.x < (verts[j].x - verts[i].x) * (pt.y - verts[i].y) / (verts[j].y - verts[i].y) + verts[i].x)) c = !c;
}
return c;
}
...where verts is an array of p5.Vector objects and pt is also a p5.Vector (though a basic object .x, .y properties will also work)
That should be a simple straight forward approach.
If you need more complex options you can look into square/rectangle packing algorithms / simulations and optimisations etc. though given the point is to set up solar panels, the real world probably the simpler setup to install and maintain on the long run will outweight potentially space saving layouts that are odd shaped.

draw function not looping as expected

I'm a beginner on here, so apologies in advance for naivety. I've made a simple image on Brackets using Javascript, trying to generate circles with random x and y values, and random colours. There are no issues showing when I open the browser console in Developer Tools, and when I save and refresh, it works. But I was expecting the refresh to happen on a loop through the draw function. Any clues as to where I've gone wrong?
Thanks so much
var r_x
var r_y
var r_width
var r_height
var x
var y
var z
function setup()
{
r_x = random()*500;
r_y = random()*500;
r_width = random()*200;
r_height = r_width;
x = random(1,255);
y= random(1,255);
z= random(1,255);
createCanvas(512,512);
background(255);
}
function draw()
{
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
Brackets.io is just your text editor (or IDE if you want to be technical) - so we can remove that from the equation. The next thing that baffles me is that something has to explicitly call your draw() method as well as the setup() method -
I'm thinking that you're working in some sort of library created to simplify working with the Canvas API because in the setup() method you're calling createCanvas(xcord,ycord) and that doesn't exist on it's own. If you want to rabbit hole on that task check out this medium article, it walks you thru all the requirements for creating a canvas element and then drawing on that canvas
Your also confirming that you're drawing at least 1 circle on browser refresh so i think all you need to focus on is 1)initiating your code on load and 2)a loop, and we'll just accept there is magic running in the background that will handle everything else.
At the bottom of the file you're working in add this:
// when the page loads call drawCircles(),
// i changed the name to be more descriptive and i'm passing in the number of circles i want to draw,
// the Boolean pertains to event bubbling
window.addEventListener("load", drawCircles(73), false);
In your drawCircles() method you're going to need to add the loop:
// im using a basic for loop that requires 3 things:
// initialization, condition, evaluation
// also adding a parameter that will let you determine how many circles you want to draw
function drawCircles(numCircles) {
for (let i = 0; i < numCircles; i++) {
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
}
here's a link to a codepen that i was tinkering with a while back that does a lot of the same things you are
I hope that helps - good luck on your new learning venture, it's well worth the climb!
Thank you so much for your help! What you say makes sense - I basically deleted the equivalent amount of code from a little training exercise downloaded through coursera, thinking that I could then essentially use it as an empty sandpit to play in. But there's clearly far more going on under the hood!
Thanks again!

How to address a shape drawn on a HTML5 canvas and change its properties?

I am beginning to explore the HTML5 canvas, and I apologize in advance for the naivety of my question. Using Flash CC, I have generated a canvas with a rectangle on it:
(function (lib, img, cjs, ss) {
var p; // shortcut to reference prototypes
// library properties:
lib.properties = {
width: 550,
height: 400,
fps: 24,
color: "#FFFFFF",
manifest: []
};
// symbols:
// stage content:
(lib.canvas_test = function() {
this.initialize();
// Layer 1
this.shape = new cjs.Shape();
this.shape.graphics.beginFill().beginStroke("#669966")
.setStrokeStyle(1,1,1).moveTo(-94,-62).lineTo(94,-62).lineTo(94,62).lineTo(-94,62).closePath();
this.shape.setTransform(198,136);
this.shape_1 = new cjs.Shape();
this.shape_1.graphics.beginFill("#FF933C")
.beginStroke().moveTo(-94,62).lineTo(-94,-62).lineTo(94,-62).lineTo(94,62).closePath();
this.shape_1.setTransform(198,136);
this.addChild(this.shape_1,this.shape);
}).prototype = p = new cjs.Container();
p.nominalBounds = new cjs.Rectangle(378,273,190,126);
})(lib = lib||{}, images = images||{}, createjs = createjs||{}, ss = ss||{});
var lib, images, createjs, ss;
Now I am stuck. How can I retrieve (and change) the color of the rectangle using a Javascript function? I had hoped that the shapes would simply be children of the canvas, but this does not seem to be the case.
The earlier answers are correct about Canvas being basically a bitmap, but EaselJS gives you a retained graphics mode, so you can change properties and update the stage/canvas to reflect them.
You are using Flash export to generate your content, so you should be able to access your elements via the exportRoot, which is created in the HTML. This is essentially the Flash "stage", represented by an EaselJS container that is defined by canvas_test in your exported library.
exportRoot = new lib.canvas_test();
You can see in the canvas_test code, each "child" is defined. Any graphics are wrapped in EaselJS Shape instances. There are also classes for handling groups (Containers), Bitmaps, Text, and animations (MovieClips).
Here is your exported code above put added to the stage:
http://jsfiddle.net/lannymcnie/b5me4xa2/
It is easy to modify shapes once they are created, but you have to define them with that in mind. The Flash export doesn't really provide you this capability, since it just exports everything as a single, chained graphics instructions list. You can however introspect it fairly easily to find the commands you want to modify. Warning: This requires EaselJS 0.7.0+ in order to work. Earlier versions will not work with this approach
The demo you provided has a single Rectangle. Unfortunately there is a bug in the current version of Flash that exports it as 2 shapes, one for the stroke, and another for the fill. This example will modify the stroke.
var shape = exportRoot.shape; // Access the shape instance that has the stroke
var stroke = shape.graphics._stroke;
stroke.style = "#ff0000"; // Set to red.
To do the fill, you can do the same thing on shape_1, but affect the _fill instead. Here is an updated sample
You can also access any of the instructions, and affect their properties. You can see a full command list in the Graphics docs (see the sidebar for the full list). Here is a quick sample modifying the first moveTo command on the stroke:
var shape = exportRoot.shape;
shape.graphics._activeInstructions[0].x = -110;
You can see a sample of that code here: http://jsfiddle.net/lannymcnie/b5me4xa2/2/ -- You will have to modify both fill and stroke to move them both :)
Canvas is basically a bitmap, it has no children. An SVG works more like you're imagining but a canvas just has pixels. If you want to change a canvas you're either going to have to go through it and find the pixels, or create a javascript object representing your drawing object (the rectangle), keep it separate from your canvas background, and redraw the the background and object when there are any changes.
[Added]
I'm not familiar with Flash CC, but as pointed out in the comment, perhaps there is some capability there already to do what the commenter and myself are describing - I'm afraid I don't know.

How to place one element inside another in raphael js?

Im trying to create an interactive seating layout like this Seats.io. However I dont need the exact features but just few things such as:
Plotting seats anywhere on the screen
Plotting list of seats from one point to another
Seats hover as circle when plotting from one mouse click point to another
After much research in Jquery and simultaneously on raphaeljs, I have decided to start working with raphaeljs. Im totally new to the vector graphics. So obviously there might be something that I may be missing. I have followed this fiddle to draw a straight line. I have also created another script to plot circles anywhere on the window(the circles will mean seats) following is the script
window.onload = function () {
var height = $(document).outerHeight(true);
var width = $(document).width();
var radius = 10;
var paper = Raphael(0, 0, width, height);
var i = 0;
$(document).click(function (e) {
i = i + 1;
var x = e.pageX;
var y = e.pageY;
var seat = paper.circle(x, y, radius)
.attr({stroke: "none", fill: "#f00", opacity: .4})
.data("i", i);
seat.mouseover(function () {
this.attr("opacity", 1);
});
seat.mouseout(function () {
this.attr("opacity", .4);
});
});
}
using the above script I'm able to plot circles(seats) on my screen. Now based on the fiddle example lines are drawn using 'path', so is it possible to load circles on every path and draw them as sequential line of circles one after the other, or do I have to take any different approach.
Also on a side note is there any opensource project or code for the Seats.io
Any help would be really appreciated
Ben from seats.io here.
http://raphaeljs.com/reference.html#Element.getPointAtLength is indeed what we use. You'll basically need to
calculate a helper path between start and end point. You already have that.
calculate the distance between seats (based on seat size): helperPath.getTotalLength() / (numberOfSeats - 1);
for each seat, call getPointAtLength and draw a circle around that
point: helperPath.getPointAtLength(distanceBetweenSeatsOnHelperPath * i++)
Obviously, it gets more interesting if you want to snap to a grid to align rows, curve rows, etc, but you should be able to get started with the above.

Using nodeJS and createJS for browser single-player RPG [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I'm creating a single player web RPG in JavaScript.
It will not be too heavy of an events-based game, but I will be loading lots of objects to the screen.
I have two questions:
1st: I've used createJS to load my bitmaps, but noticed severe lag when I loaded several objects to the screen at once and animated them. I'm wondering if there is a better library than createJS to load objects.
2nd: I was planning on using PHP for user profiles, stats, etc... but found writing AJAX calls to the server required several steps...
first, send javascript variable to php using jquery .get()
then update database
then send newly updated variable back by using json_encode, and echoing out the variable.
Finally, store that updated variable back in a javascript variable
I'm wondering how something like this is handled in NodeJS. I read How to decide when to use Node.js? to figure out the usage of NodeJS, and this sentence in particular, "I believe Node.js is best suited for real-time applications: online games, collaboration tools, chat rooms, or anything where what one user does with the application needs to be seen by other users immediately, without a page refresh." spoke to me... but I'm still not sure if I'll need to use NodeJS instead of PHP.
Thank you
EDIT:
Hi, I think I'm doing the tiling and caching incorrectly...
In my Game.php, I call several function to create/draw the objects.
Game.php:
function init() {
canvas = document.getElementById("demoCanvas");
start();
}
function start() {
stage = new createjs.Stage("demoCanvas");
stage.mouseMoveOutside = true;
//Create Objects
createWorld();
createTiles();
createPlayers();
In my function tick() I have a centerViewTo which centers the player in the viewport relative to the background (mimicking a camera).
The issue with this is, I pass in a single bitmap bgBMP that I was drawing the player relative to. If I do tiling, I'm not sure how I can draw the player relative to the background image.
centerViewTo(stage.canvas, stage, segment, {x:0, y:0, width:bgBMP.image.width, height:bgBMP.image.height});
Moreover, http://www.createjs.com/Docs/EaselJS/classes/DisplayObject.html#method_cache says I should cache each object before adding it to the container? Anyway, I get why you add all objects to the stage and then cache the stage all at once.
So I've tried that here... but it's not rendering anything:
CreateObjects.js:
var world;
var bgBMP;
var tile;
var mapWidth = 10; //Map size is 1000... so 10x10 tiles
var mapHeight = 10;
//World will be a container to hold all objects
function createWorld() {
world = new createjs.Container();
bgBMP = new createjs.Bitmap("images/bg2.png");
world.cache(0, 0, mapWidth , mapHeight );
world.addChild(bgBMP);
stage.addChild(world);
}
function createTiles() {
for (var x = 0; x < mapWidth; x++){
for (var y = 0; y < mapHeight; y++){
var tile = new createjs.Bitmap('images/myTile.png');
tile.x = x * 32;
tile.y = y * 32;
world.cache(0, 0, mapWidth , mapHeight );
world.addChild(tile);
}
}
}
I'm currently creating a RPG too with createjs, and I can display 200 characters, with their own animations and life, without lag issues.
Createjs is a really good framework, but you have to understand how it works to avoid performance issues. It's very important to separe layers in differents containers, and to cache them. For example, if the background of your game is composed with a lot of 32x32 tiles (like in RPG maker), you should cache it since it's not supposed to change during the game.
For example :
var backgroundContainer = new createjs.Container();
// mapWidth and mapHeight is the number of X and Y tiles
for (var x = 0; x < mapWidth; x++){
for (var y = 0; y < mapHeight; y++){
var tile = new createjs.Bitmap('mytile-'+i+'.png');
tile.x = x * 32;
tile.y = y * 32;
backgroundContainer.addChild(tile);
}
}
backgroundContainer.cache(0, 0, mapWidth, mapHeight);
stage.addChild(backgroundContainer);
When you cache a container, it will draw all the children in a hidden canvas, and then just draw the cached canvas on your current canvas on stage update.
If you don't cache it, just think that every time you call stage.update(), all your children will be drawn one per one on your canvas.
About NodeJS : nodeJS is really cool with the Socket.IO plugin, which use the full power of web sockets. Forget ajax if you need real time for a game : websocket is what you need. Try socket.io http://socket.io/ you will love it ;)
EDIT:
You don't use the cache well, I think you need to understand first what exactly does the cache. In my previous example, you can see we add all tiles in a container. So we have mapWidth * mapHeight tiles. Every time you call stage.update(), it will loop each tile bitmap and draw it on canvas. So if you have a 50x20 map, it will draw 1000 bitmaps every stage.update(), that's not good for performances.
If we cache backgroundContainer all tiles will be draw on an internal canvas, and when stage.update() is called it will only draw 1 image this time instead of 1000. You have to cache your world container after you add all the tiles, as in my example.
The power of createjs is that you can encapsulate your display objects as you want, this is how I organize my containers in my game :
stage
screen
scene
background -> Here I display a background image (E.g: the sky)
body
tiles -> All my background tiles (I cache this)
events -> Map events (moving NPC, my character, etc.)
overlay -> Here I display an overlay image (E.g: a fog image with 0.2 opacity)
transition -> Here I make transition when my character go to a new map
When my character move on the map, I just need to move the body container (changing X and Y properties)

Categories