I am a beginner in JS programming and I have an assignment to do something like a screensaver.
I already have two balls bouncing around on the screen but I need an algorithm to make them bounce off each other. I went through the articles here but the code is not sufficient.. or at least for me. Here is the code.
<html>
<head>
<style type="text/css">
.b {position:absolute; left:0px; top:0px; width:50px; height:50px;}
.c {position:absolute; left:0px; top:0px; width:50px; height:50px;}
</style>
<SCRIPT language="javascript">
var x =Math.random();
var y =0 ;
var h =12;
var v =22;
var g =1;
var r =0;
var q =0;
var gg = 0;
var u = Math.random() ;
var i =222;
var o = 12;
var p = 22;
var l =1;
var k =0;
var j = 0;
var mm = 0;
var height=window.innerHeight;
var width=window.innerWidth;
function moveball()
{
var b1 = document.getElementById('ball');
v=v+g;r=q;q=y;
if(y==r&&y>394&&g==5)return;
x=x+h;y=y+v;
if(x>width){x=width;h=h*-1;}
if(y>height){y=height;v=v*-1;}
if(x<0){x=0;h=h*-1;}
if(y<0){y=0;v=v*-1;}
if(v==-26&&gg==5){gg=0;g=5;}
b1.style.top=y + 'px';
b1.style.left=x + 'px';
var b2 = document.getElementById('ball2');
p=p+l;k=j;j=i;
if(i==k&&i>394&&l==5)return;
u=u+o;i=i+p;
if(u>width){u=width;o=o*-1;}
if(i>height){i=height;p=p*-1;}
if(u<0){u=0;o=o*-1;}
if(i<0){i=0;p=p*-1;}
if(p==-26&&mm==5){mm=0;l=5;}
b2.style.top=i + 'px';
b2.style.left=u + 'px';
t=setTimeout("moveball()",32);
}
</script>
</head>
<body onLoad="moveball();" >
<div id="ball" class="b"><img src="ballA.gif" width="50" height="50"></div>
<div id="ball2" class="c"><img src="trol.png" width="50" height="50"></div>
</body>
As far as I can understand my problem is that I am not handling balls that have been created by js2Draw but I am using images of balls. If you have any idea how I can do that please help I am desparate.
Right now your code allows the balls to bounce off the "walls" of your screen, but not each other. What you need to do is calculate when they get too close - that is, their centers are closer than their diameter apart.
You're making life more difficult for yourself (and for me...) by using an inconvenient naming convention - instead of having x1, x2 for the x coordinate of balls 1, 2 (even better, have x[i] for the coordinate of the ith ball), you are using different letters. I won't try to fix that but I would recommend you will get better code when you use sensible variables.
So right now you have an object at (x,y) with velocity (h,v), and a second object at (u,i) with velocity (o,p). We need to know if these two objects will "collide" during the next move step. That is - is the distance of these balls after their move step closer than 50? If a collision occurs, we can swap the velocities of balls 1 and 2 - that is approximately what happens in an elastic collision:
var xnew = x + h;
var ynew = y + v;
var unew = u + o;
var inew = i + p;
var newDist = Math.sqrt(Math.pow(xnew-unew,2) + Math.pow(ynew-inew,2));
if (newDist < 50) {
v1x = o;
v1y = p;
o = h; p = v; h = v1x; v = v1y;
}
I added these lines just before you update b2 position, and it shows that things "pretty much" work. You would want to re-arrange your code a little bit so you do this calculation before updating either position of b1 or b2, but the general gist should be obvious from this code (which does seem to produce roughly what you want, even if the physics isn't quite right - but then this is a screensaver, not a physics experiment).
Related
Can anyone please help me identify why this code isn't working? It's copied directly from a youtube tutorial so I can't see where I've gone wrong!
Thank you!
I basically want to create matrix rain, but my own version of symbols within it. Would someone be able to correctly identify what's wrong with this code? I have tried to input it into http://phptester.net/
<DOCTYPE html>
<html>
<head>
<title>Matrix Rain</title>
<style>
/*basic resets */
* {margin:0; padding: 0;}
/* adding a black bg to the background to make things clearer */
body {background: black;}
canvas {display: block;}
</style>
</head>
<body>
<canvas id="c"></canvas>
<script type="text/javascript">
var c = document.getElementbyId("c");
var ctx = c.getCont("2d");
//making the canvas full screen
c.height = window.innerHeight;
c.width = windows.innerWidth;
var ganoti = "诶比西迪艾弗艾尺艾勒艾娜吉吾艾儿"
//converting the string into an array of single characters
chinese = chinese.split ("");
var font_size = 10;
var columns = c.width/font_size; //number of columns for rain
//an array of drops - one for column
var drops = [];
//x below is the x coordinate
//1 = y co-ordinate of the drop(same for every drop initially)
for (var = x; x < columns; x++)
drops[x] = 1;
//drawing the characters
function draw () {
//Black BG for the canvas
//translucent BG to show trail
ctx.fillStyle - "rgba(0,0,0,0.05)";
ctx.fillRect(0,0, c.wdith, c.height);
ctx.fillstyle = "DB7093";
ctx.font = font_size + "px arial";
//looping over drops
for (var i = 0; i < drops.length; i++) {
var text = ganoti[Math.floor(Math.random()*ganoti.lenth)];
//x = i*font_size, y = value of drops[i]*font_size
ctx.fillText(text, i*font_size, drops[i]*font_size);
//sending the drop back to the top randomly after it has crossed
screen // it should be in comment line
//adding a randomness to the reset to make the drops scattered on the
Y axis // it should be in comment line
if (drops[i]*font_size > c.height && Math.random() > 0.975)
drops[i] = 0;
//incrementing Y coordinate
drops[i]++
}
}
setInterval(draw, 33);
</script>
</body>
</html>
}
}
phptester.net requires PHP, your code is HTML, besides has redundant double } in the end.
I have an image of a ball, a cup, and an inner and outer div that represent a throw power bar.
When the user clicks the ball, the power bar starts to increment and then decrements. When the user clicks the ball a 2nd time, the throw power bar stops and the ball is thrown.
As I have began coding this, I realized certain things are going to be extremely complicated, even though the idea itself is rather simple.
For example, I want the ball to be able to "bounce", meaning I will need to not only keep track of the balls x and y coordinates, but also a z coordinate representing depth.
When the ball falls to bounce, the z coordinate with be decremented, and the image of the ball should be scaled down in size, and when it begins bouncing back up, it should scale up in size, again based on the z coordinate. I also want the ball to bounce off the cup if the z coordinate is below a certain value by the time it reaches the cup, go into the cup if it is a certain sweet spot, or go over the cup if it's z value is over that sweet spot.
In the interest of keeping this somewhere short, I'll just post what I have so far. This example is lacking certain things that I was hoping people here could help me with.
http://jsfiddle.net/7Lsh78nw/
<html>
<head>
<style>
#ball {
position:absolute;
width:75px;
height:75px;
}
#cup1 {
position:absolute;
left:375px;
}
#outerPowerMeter {
position:absolute;
width:25px;
height:100px;
background-color:red;
}
#innerPowerMeter {
position:absolute;
width:25px;
height:100px;
background-color:black;
}
</style>
<script>
window.onload = function() {
var ball = document.getElementById("ball");
var yPos = 500;
var xPos = 400;
var zPos = 100;
var ballWidth = 75;
var ballHeight = 75;
var throwBallInterval;
var changeBallSizeInterval;
ball.style.top = yPos + "px";
ball.style.left = xPos + "px";
var cup1 = document.getElementById("cup1");
var powerMeter = document.getElementById("innerPowerMeter");
var powerMeterValue = 0;
var powerMeterHeight = 100;
var powerMeterActive = false;
var powerMeterInterval;
powerMeter.style.height = powerMeterHeight + "px";
ball.onclick = function() {
if (powerMeterActive == false) {
powerMeterActive = true;
startPowerMeter();
} else {
powerMeterActive = false;
stopPowerMeter();
throwBall();
}
}
function throwBall() {
throwBallInterval = setInterval(function() {
yPos = yPos - 1;
ball.style.top = yPos + "px";
}, 1);
changeBallSizeInterval = setInterval(function() {
zPos = zPos - 1;
ballWidth = ballWidth - 1;
ballHeight = ballHeight - 1;
ball.style.width = ballWidth;
ball.style.height = ballHeight;
}, 100);
}
function startPowerMeter() {
var increment = true;
powerMeterInterval = setInterval(function() {
if (increment == true) {
powerMeterValue = powerMeterValue + 1;
powerMeter.style.height = (powerMeterHeight - powerMeterValue) + "px";
if (powerMeterValue == 100) {
increment = false;
}
} else {
powerMeterValue = powerMeterValue - 1;
powerMeter.style.height = (powerMeterHeight - powerMeterValue) + "px";
if (powerMeterValue == 0) {
increment = true;
}
}
},1);
}
function stopPowerMeter() {
clearInterval(powerMeterInterval);
}
function detectCollision() { }
function detectGoal() { }
}
</script>
</head>
<body>
<img id="cup1" src="http://beerwar.com/game/images/cup.png">
<img id="ball" src="http://beerwar.com/game/images/ball.png">
<div id="outerPowerMeter">
<div id="innerPowerMeter"></div>
</div>
</body>
</html>
Since you posted such a detailed case, i thought i give you some pointers. Mind you: this is mostly vector math. I'm not a physicist either, but vector math isn't that complicated luckily! Some pythagoras here and there and you are set.
A good an fast library for that is glMatrix
A couple of things to get you going. Please note: it is pseudo code, but it does explain the concept of it.
Keep a vector for the position of the ball
Keep a vector for the position of the cup (where the ball should hit)
Keep a vector for the position of 'the camera' (since you want to scale the ball based on distance from the camera. Doesn't have to be accurate, just get the idea across)
Keep a vector for the 'direction of the force' you are going to apply to the ball. (this can be multiplied with the force from your force meter)
Keep a vector for the 'velocity of the ball'
Keep a vector for the 'gravity'
Your 'throw' function would become something along the lines of:
ball.velocity = throw.direction * throw.power
setInterval(tick,50);
Basicly, your 'tick' function (the function you apply every x-time)
ball.velocity += gravity; // we apply gravity to the speed of the ball. Pulling it down
ball.position = ball.position + ball.velocity // we add the velocity to the position every tick
if (ball.position.y < ball.radius) // if the ball is below its radius, it is colliding with the ground
{
ball.position.y = 0 - ball.position.y; // just invert its 'up' position, to make it not collide with the ground anymore
// to make the ball go back up again, invert its 'up' velocity. Gravity will get it down eventually
// dampening applied so it will bounce up less every time. For instance make that 0.9.
ball.velocity.y = 0 - (ball.velocity.y * dampening);
}
// the scale of the ball is not determined by its height, but by its distance from the camera
distanceFromCamera = (camera.position - ball.position).length()
ball.scale = 100 - (distanceFromCamera / scaleFactor);
// to make a simply guess if we are hitting the target, just check the distance to it.
distanceFromTarget = (cup.target.position - ball.position).length()
if (distanceFromTarget <= cup.target.radius) // if we 'hit the target'
handleHit()
This is my image sketch:
Here is a jsfiddle to work on:
<div id="a"></div>
the goal is to divide this circle into variable amount of slices.
for instance if i want 10 slices.. i can just change something to "10"
and it will show me this ring that has been divided into 10 pieces.
or '20' or '50' or '100'.
in other words some way to avoid having to deal with each individual line.
being able to rotate would be a plus.
alternatively.. i also would like the version of this.. within which only the border is divided into X slices.
either would work fine for me.
So came up with a nice little script for you. Fairly straight forward, and should work on any size circle you throw at it.
Used minimalist HTML and took care of the rest using jQuery:
HTML
<div id="a" data-lines="8"></div>
jQuery
$(document).ready(function(){
var numLines = parseInt($('#a').data('lines'));
var theta = 180/(numLines/2);
var center = $('#a').innerWidth()/2 - 1; /*-1 to account for the line width*/
var currAngle = 0;
for(var i = 0; i < numLines/2; i++){
$('<div class="lines" style="' + setAngle(currAngle) +' top: ' + center + 'px;"></div>').appendTo('#a');
currAngle += theta;
}
});
function setAngle(theta) {
return '-ms-transform: rotate('+ theta +'deg); -webkit-transform: rotate('+ theta +'deg); transform: rotate('+ theta +'deg);';
}
Example Fiddle
--Just a side note... the more lines you add the cooler it looks
Also, just playing around and added a spin animation on hover... http://jsfiddle.net/bqah9jex/4/
Here you go http://jsfiddle.net/bqah9jex/10/ .. extra compact Javascript, HTML and CSS code to represent Pie Chart.
HTML
<div id="a"></div>
CSS
#a{width:25em;height:25em;border:1em red solid;text-align:center;
border-radius:50%;background:#fff;position:relative
}
.l{width:100%;border:1px solid black;position:absolute}
Javascript
$(function () {
for (var a = 0, c = 200; c--;) {
var b = "transform: rotate(" + a + "deg)";
$('<div class="l" style="'+ ("-ms-"+ b + ";
-webkit-"+ b + ";" + b + ";") + 'top: 50%;"></div>').appendTo("#a");
a += 194; // number of lines
}
});
Demo result
http://i.stack.imgur.com/gFQZ6.png
I am attempting to use particlesDepthBlur() in place of the opacity for the "snowflakes" - which is located inside the step function, however it produces an undesired strobe effect - why? Consider the following code,
Edited for clarification:
<canvas id="canvas"></canvas>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var num = 2000;
var canvas = document.getElementById("canvas");
var width = canvas.width = 960;
var height = canvas.height = 500;
var ctx = canvas.getContext("2d");
var particles = d3.range(num).map(function(i) {
return [Math.round(width*Math.random()), Math.round(height*Math.random())];
});
function particlesDepthBlur(){
return Math.random();
console.log(Math.random());
}
function particlesDepthSize(){
return Math.floor((Math.random()*4)+1);
}
d3.timer(step);
function step() {
ctx.shadowBlur=0;
ctx.shadowColor="";
ctx.fillStyle = "rgba(0,0,0,"+particlesDepthBlur()+")";
ctx.fillRect(0,0,width,height);
ctx.shadowBlur=particlesDepthSize();
ctx.shadowColor="white";
ctx.fillStyle = "rgba(255,255,255,1)";
particles.forEach(function(p) {
p[0] += Math.round(2*Math.random()-1);
p[1] += Math.round(2*Math.random()-1) + 2;
if (p[0] < 0) p[0] = width;
if (p[0] > width) p[0] = 0;
if (p[1] < 0) p[1] = height;
if (p[1] > height) p[1] = 0;
drawPoint(p);
});
};
function drawPoint(p) {
ctx.fillRect(p[0],p[1],1,1);
};
</script>
<style>
html, body { margin: 0; padding: 0; }
</style>
Couple things:
Firstly you are calling ctx.fillStyle = "rgba(0,0,0,"+particlesDepthBlur()+")"; immediately before filling the background of the canvas.
Second, you are only calculating the blur and opacity once per frame, not per particle.
Thirdly, if you calculate it per particle (and continue to use Math.random()) then it bogs down my machine with several thousand operations per second.
Here is my
fiddle!
~Every frame I calculate 10 opacities and 10 sizes and iterate across the particles setting them per particle.~ << This was an
old version; now the opacities are all set up before step() is called, and the sizes are proportional to opacities.
edit: good job with the random falling-downward motion!
edit2: tweaking to set constant opacity and size per particle. this still runs very slowly for me, probably because you are running Math.random() 4000 times per frame. You might consider calculating a couple dozen positional vectors once per frame, and iterate across all your particles. This way every n snowflakes would be falling in the same pattern, at the benefit of much less computation needed.
Finally, perhaps consider making the 'close' snowflakes (big and bright) fall faster than the 'far' snowflakes.
<snip>
// Set up an opacity value for each particle, this will later be indexed with j
var particleOpacities = [];
particles.forEach(function(p){
particleOpacities.push(particlesDepthBlur());
});
d3.timer(step);
var j = 0;
// since j is used by both step and drawPoint, it has to be outside both functions
function step() {
ctx.shadowBlur=0;
ctx.shadowColor="";
ctx.fillStyle = "rgba(0,0,0,1)";
ctx.fillRect(0,0,width,height);
j = 0;
particles.forEach(function(p) {
p[0] += Math.round(2*Math.random()-1);
p[1] += Math.round(2*Math.random()-1) + 2;
if (p[0] < 0) p[0] = width;
if (p[0] > width) p[0] = 0;
if (p[1] < 0) p[1] = height;
if (p[1] > height) p[1] = 0;
drawPoint(p);
});
};
function drawPoint(p) {
j++; // iterate over points
var particleSize = particleOpacities[j] * 4;
ctx.shadowBlur=particleSize;
ctx.shadowColor="white";
ctx.fillStyle = "rgba(255,255,255," + particleOpacities[j] + ")";
ctx.fillRect(p[0],p[1],particleSize,particleSize);
};
The ctx.fillStyle = "rgba(0,0,0,"+particlesDepthBlur()+")"; randomly changes how much of the previous canvas is visible. It does so uniformly across the entire canvas. Sometimes if fills the screen completely with black wiping out the past views, other times it lets the last screen partially show. When it lets previous views be seen it can as much double the amount of white on the canvas, and when followed by a low opacity suddenly the quantity of white drops.
function particlesDepthBlur(){
return Math.random(0.5)+.5;
}
smooths this out
There is a web application for me to build, and rather than image map, I would like to try something more elegant.
The story is, there gonna be a global map where different continents are denoted by different colors.
Say Australia is red and Asia is green.
Will there be a way that when my mouse is hovering on the shape of Australia that my code will tell me that I am hovering on Australia by checking for the color where my cursor is currently pointing at?
I know I can check for mouse coordinates on image or something else, but I really want to get something that is not depending on pre-defined values/shapes/margins.
Any idea and suggestion would be much appreciated. Thanks a lot in advance.
It depends on what kind of element your map is. It is definitely possible for certain elements in browsers that support canvas, but not for the whole page.
See the answers to my similar question: JavaScript eyedropper (tell colour of Pixel under mouse cursor)
Merging various references found here in StackOverflow and in other sites, I did so using javascript and JQuery:
<html>
<body>
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<script src="jquery.js"></script>
<script type="text/javascript">
window.onload = function(){
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var img = new Image();
img.src = 'photo_apple.jpg';
context.drawImage(img, 0, 0);
};
function findPos(obj){
var current_left = 0, current_top = 0;
if (obj.offsetParent){
do{
current_left += obj.offsetLeft;
current_top += obj.offsetTop;
}while(obj = obj.offsetParent);
return {x: current_left, y: current_top};
}
return undefined;
}
function rgbToHex(r, g, b){
if (r > 255 || g > 255 || b > 255)
throw "Invalid color component";
return ((r << 16) | (g << 8) | b).toString(16);
}
$('#myCanvas').click(function(e){
var position = findPos(this);
var x = e.pageX - position.x;
var y = e.pageY - position.y;
var coordinate = "x=" + x + ", y=" + y;
var canvas = this.getContext('2d');
var p = canvas.getImageData(x, y, 1, 1).data;
var hex = "#" + ("000000" + rgbToHex(p[0], p[1], p[2])).slice(-6);
alert("HEX: " + hex);
});
</script>
<img src="photo_apple.jpg"/>
</body>
</html>
Here I only used canvas and one image, but if you need to use <map> over the image, it's possible too.
I hope I have helped!