Draggable.create - Want show/hide toggle on certain array/endvalues - javascript

I've hit a snag during a project I've been working on for quite some time. The client wants a spinnable dial on his frontpage, like a safe combination dial or a volume knob.
The knob has 4 endvalues, to which the object snaps (to the nearest value). The problem I've hit is that I have no idea how to make JS toggle a hide/show on a certain element once its corresponding value has been reached.
For instance, at 90 degrees rotation, I want element X to show. At 180 degrees rotation, I want element X to hide and Y to take its place/to show. Repeat in 90 degree increments for Z and A.
My current code attempt (amongst many) looks like this
var dialarray = [0,90,180,270];
var rotationSnap = 90;
Draggable.create("#Stage_Group", {
type:"rotation", //instead of "x,y" or "top,left", we can simply do "rotation" to make the object spinnable!
throwProps:true, //enables kinetic-based flicking (continuation of movement, decelerating after releasing the mouse/finger)
snap:function(endValue) {
//this function gets called when the mouse/finger is released and it plots where rotation should normally end and we can alter that value and return a new one instead. This gives us an easy way to apply custom snapping behavior with any logic we want. In this case, just make sure the end value snaps to 90-degree increments but only when the "snap" checkbox is selected.
return Math.round(endValue / rotationSnap) * rotationSnap;
if (rotation("#Stage_Group") = 90) {
sym.$("brand_awareness").show();
} else {
sym.$("brand_awareness").hide();
}
}
})
I'm using Greensocks, where support has been lacking to get me the right answer, so with some help from a more code-savvy friend (who didn't figure it out either) I turn to StackOverflow.
Can somebody please guide me to the solution here? It's driving me bonkers, even if it means ditching the current code for a working code will do, maybe I overlooked another, more logical solution towards making a rotatable object with triggers at certain values?
Thanks in advance!

This would be the code inside your snap. Updated seeing your comment
var imgRotation = Math.round(endValue / rotationSnap) * rotationSnap;
if (imgRotation == 90) {
sym.$("id1").show();
} else if (imgRotation == 180) {
sym.$("id2").show();
} else if (imgRotation == 270 ) {
sym.$("id3").show();
}
else if ((imgRotation >= 360) || (imgRotation == 0)){
sym.$("id4").show();
}
return imgRotation;

Related

How to check if an object is hitting another object during animation.

Hello and thanks for your time and help. I am building a mini golf game using HTML 5 Canvas. I have a golf ball that is able to be hit around with a specific power and direction and stoping and slowing down accordingly.
However, i am stuck on finding a optimal way of detecting wether the ball is hitting or over an obstacle on the course. I have each of the obstacle objects stored in an array. So it is easy to access the x,y,height, and width of the object. I was thinking it would be best to have a for loop that goes through each of the objects checking if the ball is hitting any of them during animation. Also the x and y of the golf ball is easily accessible, its values are stored in a dictionary.
Any suggestions of testing to see if any of the obstacles are being hit?
Here is the code on how i am testing for the boundaries and having the ball bounce back correctly
function animateGolfBall(timestamp){
if(powerBar.widthChange != 0){
context.clearRect(0, 0, canvasTag.width, canvasTag.height);
if (golfBall.x > canvasTag.width - 5 || golfBall.x < 5 ) {
golfBall.angle = 180 - golfBall.angle;
updateGolfBall();
drawEverything();
}
else if (golfBall.y > canvasTag.height - 5 || golfBall.y < 5) {
golfBall.angle = 360 - golfBall.angle;
updateGolfBall();
drawEverything();
}
else{
updateGolfBall();
drawEverything();
}
window.requestAnimationFrame(animateGolfBall);
powerBar.widthChange -= 1;
}
else{
golfBall.isMoving = false;
drawEverything();
}
}
Here is the code where the obstacles are being redrawn, and where i believe the check should be placed to see if the golf ball is hitting them
function drawObstacle(){
for(var i = 0; i < obsticles.length; i++){
obsticles[i].createSquare(obsticles[i].squareX/canvasTag.width,
obsticles[i].squareY/canvasTag.height,
obsticles[i].squareWidth/canvasTag.width,
0,
obsticles[i].squareHeight/canvasTag.height,
0,"pink",3,"yellow");
// if { need help with logic here
//And what to put here, and how ever many logical statements will be needed
// }
}
Any help or tips would be much appreciated. If you need more code or i wasn't clear on something please let me know and ill update my question.
This is called collision detection. There are many ways to deal with collisions. Depending on the shape of your objects (are they circles or squares or car-shaped) and what you want to happen when a collision occurs. Does the ball bounce back? Does it stop? Is it of the most importance that the collision is detected at the edge of the object?
You can read about simple collision detection working with either square or circle shaped objects here.

Raycasting to make an enemy jump

As stated above, I am trying to build a simple game, but I can't seem to get the enemies moving correctly. The game is a Minecraft style block-based game. The code I am using so far makes the enemy start following me when I get within a certain distance and stop following once I get a certain distance away.
The problem I am having with this script is that the enemy sort of floats off into the distance when I escape him. More importantly, I cannot for the life of me get the enemy to jump. I know that I should be using two Raycasts for this: one to detect a block in front which will make the enemy jump and another to detect below the enemy and let him fall to the level below if there is no collier at his feet? I have no idea how to go about implementing this and some help would be greatly appreciated.
The code I have thus far can be seen below:
var target : Transform; //the enemy's target
var moveSpeed = 3; //move speed
var rotationSpeed = 3; //speed of turning
var range : float=10f;
var range2 : float=10f;
var stop : float=0;
var myTransform : Transform; //current transform data of this enemy
function Awake() {
myTransform = transform; //cache transform data for easy access/preformance
}
function Start() {
target = GameObject.FindWithTag("1Player").transform; //target the player
}
function Update () {
//rotate to look at the player
var distance = Vector3.Distance(myTransform.position, target.position);
if (distance<=range2 && distance>=range) {
myTransform.rotation = Quaternion.Slerp(myTransform.rotation,
Quaternion.LookRotation(target.position - myTransform.position),
rotationSpeed*Time.deltaTime);
} else if (distance <= range && distance > stop) {
//move towards the player
myTransform.rotation = Quaternion.Slerp(myTransform.rotation,
Quaternion.LookRotation(target.position - myTransform.position),
rotationSpeed*Time.deltaTime);
myTransform.position += myTransform.forward * moveSpeed * Time.deltaTime;
} else if (distance <= stop) {
myTransform.rotation = Quaternion.Slerp(myTransform.rotation,
Quaternion.LookRotation(target.position - myTransform.position),
rotationSpeed*Time.deltaTime);
}
//lock rotation on x and y axis to zero
myTransform.eulerAngles = new Vector3(0f, myTransform.eulerAngles.y, 0);
}
The design can change really a lot. It depends how clever AI do you want ? And how realistic it should be. Firstly you should check distance and as I saw you did that. The question is what if there is a wall or something ? Maybe they are so close to each other but there is a wall between them. This is why you need raycast. So you send a raycast from enemy to player. If there is no obstacle between them AI can decide that "aye I should come after you". But here is another problem for being realistic. What if its not looking to you ? If the AI can spot the player when it looks somewhere else, it is not that cool right ? So you also check if the player is in front of the AI. Maybe we can do it like this :
var heading = target.position - transform.position;
var dot: float = Vector3.Dot(heading, transform.forward);
so if dot is -1 we can say it is directly behind and +1 means in front of it. Well, now another problem. If player should be in front of the AI to be spotted then AI can not stand right ? It should move and turn around randomly. We can work on that later if you gonan need it.
Now another problem what if you hide after an object ? What it should do ? I mean when you are running if something came between you and AI, since raycast will fail it will stop following you right ? What we can do for it ? My sugesstion store the last position of the player which AI saw. And at least go to there to check if AI can find the player there. If it cant, it may keep moving randomly. By doing this it will looks more realistic I believe.
Edit: Lol I realised that i just improved you design and forgot to answer what exactly you asked.
Firstly AI shoudl know if it is grounded or not. What we need to know first distance to ground when we send raycast we gonan need it.
var distanceToGround = GetComponent<Collider>().bounds.extents.y;
function boolean isGrounded(){
return Physics.Raycast(transform.position, -Vector3.up, distanceToGround + 0, 1);
}
AI should send a raycast not from its head more like below the knees. Not send it too far away just a little distance will be enough. It is just to understand it there is an obstacle. And also send another raycast but this time now below the knees. From the jump height. And if it dont hit anything we can decide that there is an obstacle (first raycast says that) but AI can jump over it (second raycast says that). After deciding it, if AI also grounded that means it can jump and pass trough the obstacle.
Lets say this is the part 1. If you want me to keep telling, I can write another part for you. Have a nice day !

Detecting irregular Shape

Leading up from this question Detecting mouse coordinates with precision, I have learnt quite a bit in the past few days. Here are what I picked as best learning resources on this topic:
http://gamedev.tutsplus.com/tutorials/implementation/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space/
http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/quadtrees-r1303
http://jsfiddle.net/2dchA/2/
The code in (3) works in JSFiddle but breaks at this section in my testing environment (VS2012):
var myTree = new Quadtree({
x: 0,
y: 0,
width: 400,
height: 300
});
with the message Quadtree is undefined in IE. FF & Chrome just gloss over it and display an empty page. I couldn't sort it out. Question 1: Can someone help out with that?
My main question:
I have a region (parcels of land like a map) with about 1500 parcels drawn in html5, not jpg or png images. It is a lot of lines of code to complete that but the rendering is great, so I am keeping it that way. I intend to have a mouseover event tell me which parcel I am standing on when the mouse stops. As you will see in the previous question referred my previous attempts were not impressive. Based on the learning I have been doing, and thanks to Ken J's answer/comments, I would like to go with this new approach of slicing up my canvas into say 15 quads of 100 objects each. However, I would like some guidance before I take another wild dive the wrong way.
Question 2: Should I slice it up at creation or should the slicing happen when the mouse is over a region, ie, trail the mouse? The latter sounds better to me but I think I can do with some advice and, if possible, some start out code. The quadtree concept is completely new to me. Thanks.
Can't help with question 1.
You should definitely build the tree as early as possible, given that the objective is to get the page to respond as quick as possible once the user clicks somewhere.
Keep the tree for as long as the user interacts with the 2d area. Updating a quad tree shouldn't be too hard, so even if the area changes contents, you should be able to reuse the existing tree (just update it).
Given the fact that your draw area is well know i see no advantage in a QuadTree over a spacial hash function. This function will give you an integer out of an (x,y) point.
var blocWidth = 20;
var blocHeight = 20;
var blocsPerLine = ( 0 | ( worldWidth / blocWidth) ) + 1 ;
function hashPoint(x,y) {
return ( 0 | (x/blocWidth)) + blocsPerLine*(0|(y/blocHeight));
}
once you built that, hash all your parcels within an array :
parcelHash = [];
function addHash(i,p) {
if (!parcelHash[i]) { parcelHash[i]=[ p ]; return; }
if (parcelHash[i].indexOf(p) != -1 ) return;
parcelHash[i].push(p);
}
function hashParcel (p) {
var thisHash = hashPoint(p.x,p.y); // upper left
addHash( thisHash, p);
thisHash = hashPoint(p.x+width, p.y); // upper right
addHash(thisHash, p);
thisHash = hashPoint(p.x, p.y+p.height); // lower left
addHash(thisHash, p);
thisHash = hashPoint(p.x+width, p.y+p.height); // lower right
addHash(thisHash, p);
};
for (var i=0; i<allParcels.length; i++) { hashParcel(allParcels[i]) };
now if you have a mouse position, you can retrieve all the parcels in the
same block with :
function getParcels(x,y) {
var thisHash = hashPoint(x,y);
return parcelHash[thisHash];
}
I'll just give you few tips in addition to what others have said.
... have a mouseover event tell me which parcel I am standing on ...
From your other messages I conclude that parcels will have irregular shapes. Quadtrees in general work with rectangles, so you'd have to calculate the bounding rectangle around the shape of the parcel and insert that rectangle in the quadtree. Then are when you want to determine whether mouse is over a parcel, you'll query the quadtree which will give you a set of parcels that might be under the mouse, but you'll have to then do a more precise check on your own to see if it indeed is.
... when the mouse stops.
From your other questions I saw that you try to detect when the mouse has "stopped". Maybe you should look at it this way: mouse cursor is never moving, it's teleporting around the screen from previous point to next. It's always stopped, never moving. This might seem a bit philosophical, but it'll keep your code simpler. You should definitely be able to achieve what you intended without any setTimeout checks.
... slicing up my canvas into say 15 quads of 100 objects each.
... Should I slice it up at creation or should the slicing happen when the mouse is over a region
You won't (and can't) do slicing, quadtree implementation does that automatically (that's its purpose) when you insert or remove items from it (note that moving the item is actually removing then re-inserting it).
I didn't look into the implementation of quadtree that you're using, but here are two MX-CIF quadtree implementations in case that one doesn't work out for you:
https://github.com/pdehn/jsQuad
https://github.com/bjornharrtell/jsts/tree/master/src/jsts/index/quadtree
The problem in question 1 probably happens because jsfiddle (http) page is trying access quadtree.js which is on https

Check if two objects are facing eachother

I've searched all over and couldn't find an answer to this seemingly common question, surprisingly. The problem I'm currently facing is checking if the player is facing an enemy, then if so within what range of the players' view (adjustable) and if it's within that range then move away in the nearest safe direction.
Here's a picture :D
So, how would I accomplish this? I have the x, y, and direction, of every ship object. This is my last failed attempt, attempting to consider that the player's direction will be exactly 180 degrees away from the enemy's direction relative to the player.
var direction=Math.direction(this.x,this.y,player.x,player.y,1),
playerview=Math.abs(direction)-Math.abs(player.direction-180)
if(Math.abs(playerview)<10) {
console.log('in view')
this.xVelocity+=AI.speed*Math.sin(playerview*Math.PI/180)
this.xVelocity+=AI.speed*Math.cos(playerview*Math.PI/180)
}
In this example, 10 would be the range. Of course, I've only managed to make ships rotate to the right, so aside from the detection only working on half a circle I can't make the enemy go to the right side either. Any ideas?
In Your code, You are modifying this.xVelocity twice instead of modifying this.yVelocity.
I guess, Math.direction is not in the JavaScript/ECMA standard. Are You sure, You are using it correctly? Consider Math.atan2.
Moreover, You should provide a definition of "facing each other".
If it's "seeing each other", then Your comment "in view" is misleading.
But the main issue is:
Math.abs(angleInDegrees) modifies the angle!
The correct way to build an absolute value of an angle is:
while (angleInDegrees < 0)
{
angleInDegrees += 360;
}
// If necessary, add this too:
while (angleInDegrees >= 360)
{
angleInDegrees -= 360;
}
-10 and 350 are identical, -10 and 10 are 20 degrees apart.
For further explanation, let's call the code above normalizeAngle
(Note: For huge values, the loop may run very long or even forever. If such values may occur, this should be checked.)
The following should do the trick:
playerview = normalizeAngle(direction - player.direction - 180)
if (playerview < range || playerview > 360-range) {
By the way: "playerview" should be the mininum from the player's field of view and the enemy's field of view.

Why does my my gravity work in this?

http://davzy.com/gameA/
I can't figure out a smart way to get gravity. Now with this it detects which block the character is over but it does't drop to that block!
Is there a better way to do gravity? I'd like to do this without a game library.
I don't know what you mean by "get gravity"; your question is unclear. I assume that if you can detect when the block is over, you can use the following formula:
s(t) = ut + 1/2at2
Where s is the distance at time t, u is the initial velocity (which in your case would be zero), and a is the acceleration (on Earth this is 9.8m/s2). Essentially you would be adjusting the top position of your object based on the value you get at time t (so original top position of object + s(t)). I would imagine you would use some sort of animation loop. Perhaps a setInterval. Maybe others with more experience in Javascript animation can chime in about the best way to implement this. However, this would be the formula that you would be using to figure out where the object is at time t, if it falls.
Basically gravity in a platformer goes like this:
var currentGrav = 0.0;
var gravAdd = 0.5; // add this every iteration of the game loop to currentGrav
var maxGrav = 4.0; // this caps currentGrav
var charPosY = getCharPosY(); // vertical position of the character, in this case the lower end
var colPosY = getColDow(); // some way to get the vertical position of the next "collision"
for(var i = 0; i < Math.abs(Math.ceil(currentGrav)); i++) { // make sure we have "full pixel" values
if (charPosY == colPosY) {
onGround = true;
break; // we hit the ground
}
onGround = false;
charPosY++;
}
Now to jump one could simply do this:
if (jumpKeyPressed && onGround) {
currentGrav = -5.0; //
}
You can, if you want(and understand C), check out my game for a basic platformer(with moving platforms) here:
http://github.com/BonsaiDen/Norum/blob/master/sources/character.c

Categories

Resources