How to rotate an array of canvas rectangles - javascript

I'm creating a Pentomino puzzle game for a final project in a class I'm taking. I've created all dozen of the required puzzle pieces and can drag those around here. And I've tried this code to rotate the array (without using canvas.rotate() & located at the very bottom of the fiddle), it basically swaps the X & Y coordinates when drawing the new piece:
var newPiece = targetPiece;
pieces.splice(pieces.indexOf(targetPiece), 1);
targetPiece = null;
console.log(newPiece);
var geometry = [];
for (var i = 0; i < newPiece.geometry.length; i++) {
geometry.push([newPiece.geometry[i][3], newPiece.geometry[i][0]]);
}
var offset = [newPiece.offset[1], newPiece.offset[0]];
console.log(geometry);
console.log(offset);
newPiece.geometry = geometry;
newPiece.position = geometry;
newPiece.offset = offset;
pieces.push(newPiece);
console.log(pieces);
for (var j = 0; j < pieces.length; j++) {
draw(pieces[j]);
}
This doesn't work properly, but has promise.
In this fiddle, I've isolated the problem down to a single piece and tried to use canvas.rotate() to rotate the array by double clicking, but what's actually happening is it's rotating each piece of the array (I think), which results in nothing happening because each block of the array is just a 50x50 rectangle and when you rotate a square, it still looks just like a square.
function doubleClickListener(e) {
var br = canvas.getBoundingClientRect();
mouse_x = (e.clientX - br.left) * (canvas.width / br.width);
mouse_y = (e.clientY - br.top) * (canvas.height / br.height);
var pieceToggle = false;
for (var i = 0; i < pieces.length; i++) {
if (onTarget(pieces[i], mouse_x, mouse_y)) {
targetPiece = pieces[i];
rotate(targetPiece);
}
}
}
function rotate() {
targetPiece.rotationIndex = targetPiece.rotationIndex === 0 ?
1 : targetPiece.rotationIndex === 1 ?
2 : targetPiece.rotationIndex === 2 ?
3 : 0;
for (var j = 0; j < pieces.length; j++) {
draw(pieces[j]);
}
}
Just FYI, I've tried creating the puzzle pieces as individual polygons, but could not figure out how to capture it with a mousedown event and move it with mousemove, so I abandoned it for the canvas rectangle arrays which were relatively simple to grab & move.
There's a brute force solution to this, and a total rewrite solution, both of which I'd rather avoid (I'm up against a deadline-ish). The brute force solution is to create geometry for all possible pieces (rotations & mirroring), which requires 63 separate geometry variants for the 12 pieces and management of those states. The rewrite would be to use fabric.js (which I'll probably do after class is over because I want to have a fully functional puzzle).
What I'd like to be able to do is rotate the array of five blocks with a double click (don't care which way it goes as long as it's sequential 90° rotations).
Approaching a usable puzzle:
With lots of help from #absolom, here's what I have, you can drag with a mouse click & drag, rotate a piece by double clicking it, and mirror a piece by right clicking it (well, mostly, it won't actually rotate until you next move the piece, I'm working on that). The Z-order of the pieces are manipulated so that the piece you're working with is always on top (it has to be the last one in the array to appear on top of all the other pieces):
Pentominoes II
The final solution
I've just handed the game in for grading, thanks for all the help! There was a lot more tweaking to be done, and there are still some things I'd change if I rewrite it, but I'm pretty happy with the result.
Pentominoes Final

Quick & Dirty:
The quick & dirty solution is when 2+ pieces are assembled you create a single image of them (using an in-memory canvas). That way you can move / rotate the 2-piece-as-1-image as a single entity.
More Proper:
If the 2+ piece assembly must later be disassembled, then you will need the more proper way of maintaining transformation state per piece. That more proper way is to assign a transformation matrix to each piece.
Stackoverflow contributor Ken Fyrstenberg (K3N) has coded a nice script which allows you to track individual polygons (eg your rects) using transformation matrices: https://github.com/epistemex/transformation-matrix-js

Does this code do what you need? The rotate method looks like this now:
function rotate(piece) {
for (i = 0; i < piece.geometry.length; i++) {
var x = piece.geometry[i][0];
var y = piece.geometry[i][2];
piece.geometry[i][0] = -y;
piece.geometry[i][3] = x;
}
drawAll();
}
I simplified how your geometry and positioning was handled too. It's not perfect, but it can gives you some hints on how to handle your issues.
Please note that this solution works because each piece is composed of blocks with the same color and your rotations are 90 degrees. I only move the blocks around to simulate the rotation but nothing is rotated per-se. If you build your pieces differently or if you need to rotate at different angles, then you would need to go with another approach like transformation matrices.
UPDATE
Here is a better solution: fiddle

Related

How to make sure that a shape has straight corners

i'm looking for a way to draw a shape on an image, get the coordinates, then make minor corrections to have a perfect square or diamond.
I have a floor plan and i'm trying to highlight certain areas. Since i'm drawing over the image, i can't always get it a perfect shape and manual corrections takes time.
I would like to draw over the image, then pass it to a functiton which makes sure that each angles are 90 degrees, or it fixes the coordinates. The shape is always gonna be a square or a rectangle. All I want are the corrected coordinates so they can be saved in a file.
Here's a sample of the image i'm working with, along with one location:
var loc6 = [{x:711, y:596}, {x:787, y:595}, {x:784, y:641}, {x:711, y:641}];
https://imagebin.ca/v/2zjcnTJCRL2n
Math isn't my biggest asset, i've got the function below, but it only works to make a perfect square on squares, and messes up diamonds.
function fixRectangle(coords){
var precision = 8;
if(coords[0].y - coords[1].y < precision){
coords[0].y = coords[1].y;
}
if(coords[1].x - coords[0].x < precision){
coords[0].x = coords[1].x;
}
if(coords[2].y - coords[3].y < precision){
coords[2].y = coords[3].y;
}
if(coords[2].x - coords[3].x < precision){
coords[2].x = coords[3].x;
}
return coords;
}
(I do use jquery in case it is required)
Thanks for your help !

Javascript sprites moving between two points

I'm wanting to get some sprites moving between two points in my (very basic) javascript game. Each sprite is randomly placed in the level, so I want them to move back and forth between their base position. I have the code below
function Taniwha(pos) {
this.basePos = this.pos;
this.size = new Vector(0.6, 1);
this.move = basePos + moveDist(5,0));
}
Taniwha.prototype.type = "taniwha"
var moveSpeed = 4;
Taniwha.prototype.act = function(step) {
this.move = ???
and this is where I get stuck. I'm not sure how to tell it to go left, back to base pos, right then back to base pos again (I plan to loop this). Does anyone have any advice? (also using Eloquen Javascript's example game as an outline/guide for this, if how I'm doing things seems odd!)
For horizontal movement, change x coordinate of the position.
var pos = { x: 1, y: 2 };
pos.x++ ; // This will move right
pos.x-- ; // This will move left
Likewise for vertical movement. You also need to update the coordinates after change for the object which you are drawing.
In truth ,there are lots of library to develop a game.
Use those, control a sprite is very easy.
Like:
Pixijs
CreateJS
Both of them are opensource project, you can watch and learn the source.
And have lots of examples and document.

createjs struggling with hitTest()

I am populating the canvas with small circles to form a shape and would like to destroy some of the circles where ever user clicks on the screen using the following function.
dotsArray : is the array of all circles
dot.ball: is the circle being drawn
bomb: is the circle drawn using user input being taken by the mouse click and hold.The bomb scales up in size as the mouse is pressed
function onMouseDown(event){
bomb.x = event.stageX;
bomb.y = event.stageY;
bomb.active = true;
}
function decimateBalls(){
for (var i = 0; i < dotsArray.length; i++){
for ( var j = 0; j < dotsArray[i].length; j++){
var dot = dotsArray[i][j];
var pt = dot.ball.localToLocal(dot.ball.x, dot.ball.y,bomb);
if(bomb.hitTest(pt.x,pt.y)){
dot.setType("empty"); // this changes dot's circle to white making it seem invisible
}
}
}
}
When I use the above code, even though i calculate the location of the small dots with respect to the bomb circle being drawn, the dots that disappear are the ones that are a lot offset from the bomb circle being drawn.
Am i doing something obviously wrong? Is there a better way to approach this problem?
Thanks a lot for your time.
I used the following work around to get the desired result.
made sure everything is added to stage. got rid of containers.
Use if(bomb.hitTest(dot.ball.x - bomb.x,dot.ball.y - bomb.y)) and got rid of localToLocal() function provided by createjs to find local coordinates of an object with respect to another object.
Hope this helps someone who comes across a similar issue.

Efficient way to light up/cast shadows on a voxel terrain

I'm using a BufferGeometry and some predefined data to create an object similar to a Minecraft chunk (made of voxels and containing cave-like structures). I'm having a problem lighting up this object efficently.
At the moment I'm using a MeshLambertMaterial and a DirectionalLight which enables me to cast shadows on voxels not in view of the light, however this isn't efficient to use for a large terrain because it requires a very large shadow map and will often cause glitchy shadow artifacts as a result.
Here's the code I'm using to add the indices and vertices to the BufferGeometry:
// Add indices to BufferGeometry
for ( var i = 0; i < section.indices.length; i ++ ) {
var j = i * 3;
var q = section.indices[i];
indices[ j ] = q[0] % chunkSize;
indices[ j + 1 ] = q[1] % chunkSize;
indices[ j + 2 ] = q[2] % chunkSize;
}
// Add vertices to BufferGeometry
for ( var i = 0; i < section.vertices.length; i ++ ) {
var q = section.vertices[i];
// There's 1 color for every 4 vertices (square)
var hexColor = section.colors[i / 4];
addVertex( i, q[0], q[1], q[2], hexColor );
}
And my 'chunk' example: http://jsfiddle.net/9sSyz/4/
A screenshot:
If I were to remove the shadows from my example, all voxels on the correct side would be lit up even if another voxel obstructed the light. I just need another scalable way to give the illusion of a shadow. Perhaps by changing vertex colors if not in view of the light? It doesn't have to be as accurate as the current shadow implementation so changing the vertex colors (to give a blocky vertex-bound shadow) would be enough.
Would appreciate any help or advice. Thanks.
Generally, if you have large terrains, the idea is to split the scene into more cascades and each cascade has its own shadow map. Technique is called CSM - cascaded shadow maps. Problem is, I haven't heard of an webGL example that implements this technique. CSMs are used on dynamic scenes. But I'm not sure how easy would be to implement this with Three.js.
Second option is adding ambient occlusion, as suggested by WestLagnley, but it's just an occlusion, not a shadow. Results are very different.
Third option, if your scene is mostly static - baked shadows. So, preprocessed textures that you simply apply to the terrain etc. To support dynamic objects, just render their shadow maps and apply those to some geometry that just mimics shadowed area (perhaps, a plane that hovers slightly above ground and receives the shadow etc).
Any combination of the techniques mentioned is also an option.
P.S. Could you also supply a screenshot, fiddles fail to load.

Javascript: Simple Particle Motion, Particle Elastically Bouncing Off Other Particle

I've created this rather simple javascript; balls or 'molecules' moving around the screen. I was hoping to add to the functionality that when one ball comes into contact with another, they swap velocities. We don't need to worry about any angles, just when they come into contact with each other, the velocities swap. (Instead of changing the velocities though, in the code linked I've just coded a colour change)
I've been trying to call the function 'someplace' to recognise when the molecules touch, but I've had no luck with that. I don't really understand why.
Link to code:
http://jsbin.com/arokuz/5/
There seems to be three main problems:
The molecules seem to be randomly changing, rather than when two molecules touch.
When one sets the array to have say, 3 molecules, only two appear, the first is actually there, but unresponsive to .fillstyle changes, so invisible against the canvas
With the function method I would only be able to recognise when molecules in series (1 and 2 or 4 and 5) in the array touch...how could I check all the molecules?
You are only comparing a molecule with 2 other ones, which in fact might be anywhere.
Collision detection is a topic quite hard to solve, but if you want to have your idea
working quickly you might go for a n^2 algorithm with 2 nested for loops.
the code is quite expected :
// collision
for(var t = 0; t < molecules.length-1; t++)
for(var tt = t+1; tt < molecules.length; tt++) {
var p1 = molecules[t];
var p2 = molecules[tt];
if (sq(p1.x-p2.x) +sq(p1.y-p2.y) < sq(p1.radius+p2.radius) )
{
p1.collided = 8; // will diplay for next 8 frames
p2.collided = 8; // .
}
}
the fiddle is here :
http://jsbin.com/arokuz/10
The reason only two appear when three are made isn't because the first one doesn't render it is rather the last one doesn't, this is because of how you draw them by comparing its distance with the next one in the list - as it is the last there is no next and thus throws a null error and continues (check the console).
The reason why they seem to "randomly" detect collisions or not is because they are not checking against all other molecules - only the next in the list, unfortunately the only simply way to do it would be to go through all other balls for every ball and checking.
To get the molecules to detect distance you could use the pythagorean theorem, I typically use it such as:
var distx = Math.abs(molecule1.x - molecule2.x);
var disty = Math.abs(molecule1.x - molecule2.y);
var mindist = molecule1.radius + molecule2.radius;
return Math.sqrt(distx*distx+disty*disty) < mindist;

Categories