Add new elements based on position and rotation angle of main element - javascript

I'm building a game in vanilla javascript where you can spot fishes on a radar. What I'm trying to achieve is the following:
I want objects (fish) to show up randomly on the position of the dial (randomly on the width/height) while its spinning. I am able to get the angle of the dial, and the position, but I have no idea how to calculate the position of the new objects.
My current ugly solution involves creating a temporary div inside the dial, get the position, and use those for the new object, but it doesn't really work properly.
See this fiddle for what I have so far
function createNewFish() {
// Create new fishies
/*
const pos = document.getElementById('dial').getBoundingClientRect();
const degrees = getDialDegrees();
console.log(pos)
console.log(degrees)
// Calculate position for fish?
*/

For anyone attempting to do the same, I've managed to solve it using the following solution:
When you have a dial that spins, you can fill the dial with some equal divs (I used 9) like so:
function DialGenerator() {
for(let i=0;i<9;i++) {
const insideDial = document.createElement('div');
insideDial.classList.add('dial-inside')
insideDial.setAttribute('id', 'dial-inside-'+i)
document.getElementById('dial').appendChild(insideDial)
}
}
Then if you want to show elements on random positions on the dial (like my radar needs), you can just get a random div inside the dial using Math.random() and get the position of this div:
function getPosition() {
const n = getRandomNumber(1, 6);
// Get a random position on the dial for the fish to appear on
const dialPosition = document.getElementById('dial-inside-'+n).getBoundingClientRect();
return {'top':dialPosition.top, 'left':dialPosition.left}
}
This returns the position of the div on the dial, which you can use to place your elements on the radar.
Hope this helps someone!

Related

How do I rotate around a point towards the mouse in PaperJS?

I'm creating a simple game using PaperJS and I'm currently stuck on a small part of it.
In the game, there is a player (just a circle) who has two hands (two smaller circles)
I want the hands to always point towards the mouse position, but I can't figure out the equation needed to do so.
Here's some of the code I have so far, I just need help filling in the blank...
view.onMouseMove = function(event) {
var mouseX = event.point.x;
var mouseY = event.point.y;
var rotation = ???
playerHands.rotate(rotation, view.center)
}
Here is a diagram of what I'm trying to accomplish:
is really simple:
function onMouseMove(event) {
let delta = (event.point - player.position);
player.rotation = delta.angle+90;
}
the idea here is you can use two Points to do Vector-Geometry.
more in depth descriptions are in the Vector-Geometry Tutorial
there is a +90 offset needed to align mouse with top of player as paperjs sees the x axis as 0° for rotation.
i have created a working example in sketch.paperjs.org
the above player.rotation is only working if the Player Group has its .applyMatrix set to false.
additionally i set the Player-Group pivot point to the big circle center at creation:
let player = new Group(circle, handleleft, handleright);
player.applyMatrix = false;
player.pivot = circle.bounds.center;
player.position = position;

Limit camera rotation on the Y axis

I am using JSModeler to display OBJ files. It internally uses THREE.JS and creates a PerspectiveCamera. What I need is to limit the movement of the camera on the Y axis so not to go underneath the object. I know how to do this with THREE.OrbitControls but this doesn't work with JSModeler. Is there a way to directly control the camera movement? Thanks.
jsmodeler creates its own set of controls which it stores in JSM.navigation object.
viewer = new JSM.ThreeViewer ();
camera_object = viewer.navigation.camera
The drawLoop function takes in values in this viewer.navigation.camera and renders them on the canvas. So, suppose if you change the values in the viewer.navigation.camera, and call drawCallback(), the changes would get rendered.
viewer.navigation.camera.eye.x = 1; // Any value you want
viewer.navigation.camera.eye.y = 1; // Any value you want
viewer.navigation.camera.eye.z = 1; // Any value you want
viewer.navigation.drawCallback();

Swap Items using basiljs

I am pretty new to the whole basiljs world. So this might be a very basic question. I wasn't able to figure it out on my own however… 
I am trying to create a simple script that swaps two Items that are selected on the same page.
I was able to get the image frame to swap, however it leaves the frames content in the same position. Here is waht it looks like:
#includepath "~/Documents/;%USERPROFILE%Documents";
#include "basiljs/bundle/basil.js";
function draw() {
var selItems = b.selections();
var selItems0x = b.itemX(selItems[0]);
var selItems1x = b.itemX(selItems[1]);
var selItems0y = b.itemY(selItems[0]);
var selItems1y = b.itemY(selItems[1]);
b.itemX(selItems[0], selItems1x);
b.itemX(selItems[1], selItems0x);
b.itemY(selItems[0], selItems1y);
b.itemY(selItems[1], selItems0y);
}
b.go();
Now my question is: How can I call on the frames content. Obviously I want that one the move the same with the frame.
Thanks for your help, I am eager to learn more!
Raphy
Even though it is not the "basiliy" way I suggest using InDesign build in functions. You can mix them with Basil Code. Basil doesn't care. There is the possibility to fit elements into its frame or center them.
Try this snippet:
#includepath "~/Documents/;%USERPROFILE%Documents";
#include "basiljs/bundle/basil.js";
function setup(){
var sel = b.selections();
var gb0 = sel[0].geometricBounds;
var gb1 = sel[1].geometricBounds;
// swap them
sel[0].geometricBounds = gb1;
sel[1].geometricBounds = gb0;
// see the different fit options
// http://yearbook.github.io/esdocs/#/InDesign/FitOptions
sel[0].fit(FitOptions.CENTER_CONTENT);
sel[0].fit(FitOptions.PROPORTIONALLY);
}
b.go();
The problem is that in InDesign a (image) graphic and its containing frame are treated as two separate objects, which means, if you only move the frame, the graphic in it does not move along.
In basil.js you have the method b.transformImage() to move a frame along with its graphic, but it is rather cumbersome to use, as you need to pass along the position as well as the scale of the image.
Alternatively you could move the graphic in a second step. Make sure first that the item actually contains a graphic (instead of being a simple oval etc.) and if that's the case move it to the same position as its parent frame. You can access a frames graphic by using frame.graphics[0].
The script would look like this then:
#includepath "~/Documents/;%USERPROFILE%Documents";
#include "basiljs/bundle/basil.js";
function draw() {
var selItems = b.selections();
var selItems0x = b.itemX(selItems[0]);
var selItems1x = b.itemX(selItems[1]);
var selItems0y = b.itemY(selItems[0]);
var selItems1y = b.itemY(selItems[1]);
b.itemX(selItems[0], selItems1x);
b.itemY(selItems[0], selItems1y);
if(selItems[0].graphics.length > 0) {
b.itemX(selItems[0].graphics[0], selItems1x);
b.itemY(selItems[0].graphics[0], selItems1y);
}
b.itemX(selItems[1], selItems0x);
b.itemY(selItems[1], selItems0y);
if(selItems[1].graphics.length > 0) {
b.itemX(selItems[1].graphics[0], selItems0x);
b.itemY(selItems[1].graphics[0], selItems0y);
}
}
b.go();
Note that this will not work if the top left corner of the image is cropped by the frame. In this case you would need to figure out where the top left corner of the graphic actually is and then offset the graphic accordingly after moving it.
Btw., the basil.js team is aware that the transforming of images is somewhat overly complicated and there is a plan to simplify this process in the future.

ZoomTo boundingBox in SearchBox.onSelect with HERE maps and place

I am using nokia.places.widget.SearchBox together with nokia.maps.map.Display.
You can use onSelect function of the SearchBox to perform operations when a user picks an items from the results list.
What I need to do is center and zoom the map to the picked place. My problem is concerning zooming because I don't know what level to use.
I noticed that some places have boundingBox (to use with the zoomTo function of the Display component) property but other doesn't. I could use category ('administrative-region', 'street-square', etc.) but it is other than precise and moreover I can't find a list of possible category codes.
Any suggestion?
To get the map to move/zoom to a location when a suggestion is chosen, you will need to implement an onResults handler:
var fromSearchBox = new nokia.places.widgets.SearchBox({
targetNode: "fromSearchBox",
template: "fromSearchBox",
map: map,
onResults: function (data) {
// Your code goes here //
}
});
As you noticed the data field may or may not hold a bounding box. This is because only a few locations cover a defined area, most are point addresses.
For the subset which have a boundingbox you can do the following:
if (data.results.items[0].boundingBox){
map.zoomTo(data.results.items[0].getBoundingBox());
}
For the remainder the answer will depend upon what you are trying to achieve, but you could try any of the following:
Move to the location on the map without altering the zoom. (i.e. let the user decide)
map.set("center", data.results.items[0].position);
Move to the specified bounding box for a point object at the
specified location.
var obj = new nokia.maps.map.StandardMarker(startPoint);
map.zoomTo(obj.getBoundingBox());
Or alternatively: map.zoomTo(nokia.maps.geo.BoundingBox.coverAll([startPoint]));
Define a bounding box surrounding the point location and zoom to that instead
startPoint =data.results.items[0].position;
bottomLeft = new nokia.maps.geo.Coordinate(startPoint.latitude - 0.1,
startPoint.longitude + 0.1);
topRight = new nokia.maps.geo.Coordinate(startPoint.latitude + 0.1,
startPoint.longitude - 0.1);
map.zoomTo(nokia.maps.geo.BoundingBox.coverAll([topRight, bottomLeft]));
Additionally, Display.zoomTo() can also take an additional parameter, so if you use map.zoomTo(BoundingBox, true) you will also keep the current center for the map on screen, and this may give more context to a user.

How to make a game out of an html table?

I'm basically trying to make a game that involves a grid. Here's what I have so far (it'll help to see the game before I explain what I need to happen):
Javascript (see jsfiddle for html):
var score = 0;
var points = function(val, box) {
var noise = Math.round(Math.round(0.1*val*Math.random()*2) - 0.1*val);
score = score + (val + noise);
var square = document.getElementById(box);
square.innerHTML = val + noise;
square.style.display='block';
setTimeout(function() {
square.style.display='none';
}, 400);
document.getElementById("out").innerHTML = score;
}
http://jsfiddle.net/stefvhuynh/aTQW5/1/
The four red squares at the bottom left of the grid needs to be the starting point in the game. When you click on one of those boxes, you can then travel along the grid by clicking adjacent boxes. Basically, I need to make it so that the player can only travel up, down, left, and right from the box that they just clicked on. I don't want the points function to be invoked when the player clicks on a box that they're not supposed to click on.
Additionally, I need to make it so that the player can't click on another box until 400 ms have elapsed.
I'm relatively new to programming so any help at all would be great. I would also appreciate tips on how to make the program more efficient, if there's a way to do that.
General idea:
I'd suggest having a similar id for all your boxes, such as box_x_y, and storing a list of strings, let's say allowedSquares.
You would then be able to write a function which, upon clicking on a box, would check if it's id is in allowedSquares, and if it is, call points(val, box) then update the contents of allowedSquares to reflect the change of position.
The point of using a standard id convention for all your boxes is that you could write getPosition(box) and getBox(intX, intY) that would parse the id strings to return you the box position, or vice-versa.
You can even make the updateAllowedSquares(clickedBox) function change the color of adjacent boxes to show they're allowed next steps.
EDIT: Some example code:
Disclaimer: these are not the code lines you're looking for.
This is only a starting kit for you, which assumes a 3x3 grid with a single-square bottom right starting position. You will have to adapt this code a bit. Also, I predict something will go wrong concerning going out of bounds. I'll let you think with this a bit, as I prefer giving food for thoughts over complete solutions in those cases...
var allowedSquares = ["box_2_2"]; // Initial list
function decodePositionFromID(boxId) {
return boxId.split("_").slice(1,2);
}
function getIDfromXY(x, y) {
return "box_" + x + "_" + y;
}
function updateAllowedSquaresList(boxID) {
// 1 - We clear the array.
allowedSquares.length = 0;
// 2 - We get the adjacent boxes IDs.
var xyArray = decodePositionFromID(boxId);
var upperBoxID = getIDfromXY(xyArray[0], xyArray[1]-1);
// Rince, repeat, and add some gameboard boundaries checks.
// 3 - We add the new IDs to the list.
allowedSquares.push(upperBoxID, ...);
}
function boxClick(val, boxID) {
// We check if the box is a valid square to play.
if (allowedSquares.indexOf(boxID) != -1) {
points(val, boxID);
updateAllowedSquaresList(boxID);
}
}

Categories