Smoothen the animation of Casino wheel - javascript

I am developing a casino based game using html5. The animation is working properly but this is not quite smooth i.e. once the wheel stops rotation I move ball as a final repositioning to smoothen the transition but it is not upto the expectation. Complete Code here
BallReposition Function - runs after I wheel stops movement for the final repositioning of the ball to give some reality to the animation.
function ballReposition(){
curX = findNearestOnCircle(curX);
if(curX > deadXRight){
sign = "-";
}else if(curX < deadXLeft){
sign = "+";
}
if(sign == "+"){
curX = parseInt(curX) + ballRepositionIncVal;
curY = Math.floor(Math.abs(getYOnCircle(curX, 130, 1)) + 0.5);
}else{
curX = parseInt(curX) - ballRepositionIncVal;
curY = Math.floor(Math.abs(getYOnCircle(curX, 130, 0)) + 0.5);
}
var xy = normalizeXY(curX, curY);
curX = parseInt(xy.split("-")[0]);
curY = parseInt(xy.split("-")[1]);
surface = document.getElementById("myCanvas");
var surfaceContext = surface.getContext("2d");
//removing older ball image.
surfaceContext.save();
// Translate to the center point of our image
surfaceContext.translate(happy.width * 0.5, happy.height * 0.5);
// Perform the rotation
surfaceContext.rotate(DegToRad(angle));
// Translate back to the top left of our image
surfaceContext.translate(-happy.width * 0.5, -happy.height * 0.5);
surface.getContext("2d").drawImage(happy, 0, 0);
surface.getContext("2d").drawImage(ball, curX, curY);
console.log(curX + curY);
surfaceContext.restore();
ballRepositionIncVal-=5;
if(ballRepositionIncVal <= 0){
clearInterval(myIntervalVar);
}
}
Other function details -
drawCanvas - loads the images and once the images are loaded it will start calling loop function which will rotate the wheel and move the ball in anticlockwise direction.
normalizeXY - used to put the ball at some discrete positions i.e. proper positions below numbers of wheel.
EDIT - Fiddle Configuration updated here

To create a realistic spinning wheel you can use a logarithmic-ish approach to reduce the speed of the wheel.
This means the angle is decremented by small per-centage for each frame. As it is per-centage you will get a smooth ending spin (you will also notice you get the infamous wagon wheel aliasing effect).
This online demo shows the loop isolated (implement as you please):
var angle = 2; /// start angle in radians
ctx.translate(w, h); /// prepare canvas for rotation (w and h = 50%)
ctx.globalAlpha = 0.67; /// optional bonus: motion blur(-ish)
loop(); /// start loop
function loop() {
ctx.rotate(a); /// use incremental rotation
ctx.drawImage(img, -w , -h);
/// spin down and only loop if angle > certain value
a *= 0.995;
/// continue if there is enough "inertia"
if (a > 0.001) requestAnimationFrame(loop);
}
The threshold value for continue the loop determines how "brutal" you want the stop to be. If you want the wheel to appear heavier (more mass) you can decrement the angle with an even tinier increment (eg. try 0.998).
For the ball to bounce around you need to resort to physics modelling, or at least pseudo-physics-modelling. This includes collision detections for all the small details on the wheel as well as sub-time-steps (ray casting) checking and positioning in z-axis.
I feel this is a bit broad to describe here on SO but find a good article on collision detection and physics simulation. Here is a good start with the basics.

Related

Rotation facing mouse not correct with p5 libraries

i am making a javascript shooter game.i want the the player to rotate towards the mouse.it is working, but the rotation was not correct.
I tried this with an image, and it works, but with the sprite itself(player1), is not.
i have asked this once before but received no answer
I am a beginner in javascript, so help would be appreciated.
I am using the p5.js libraries
Here is my code snippet:
//variables
var player1;
var gun1;
var gun2;
function preload(){
img = loadImage('rect1.png');
}
function setup(){
//creating sprites
player1 = createSprite(200,200,30,30)
gun = createSprite(player1.x,player1.y-20,5,30)
gun.shapeColor = "black"
player1.addImage("player",img)
player1.scale = 0.2
}
function draw(){
canvas = createCanvas(displayWidth-20, displayHeight-120);
background("#32CD32");
push()
gun.x = player1.x;
gun.y = player1.y-15;
// functions to move
//up
if(keyDown("up")){
player1.y = player1.y - 5;
}
//down
if(keyDown("down")){
player1.y = player1.y + 5;
}
//right
if(keyDown("right")){
player1.x = player1.x + 5;
}
//left
if(keyDown("left")){
player1.x = player1.x - 5;
}
angleMode(DEGREES)
imageMode(CENTER)
let a = atan2(mouseY - height / 2, mouseX - width / 2);
translate(width/2, height/2);
//rotate(a)
player1.rotation = a
//image(img,0,0,40,40)
pop()
drawSprites();
}
I think I'm using a dated version of p5.play, so there's not much in your code that works for me, but here's what I think is going on based on what you're saying.
If you want to understand what the deal is with atan2(), you first have to understand atan(). Basically, you have the ordinary trig functions sin, cos, and tan. Then you have the inverse trig functions arcsin, arccos, and arctan (abbreviated asin, acos, and atan). The arctan function is useful because you can input a slope and it will give you the angle of that slope. There's a catch, though; atan will only give values between -pi/2 and pi/2. This covers all non-vertical lines, but what if you wanted to use it for a vector or something that has direction? atan2() solves that problem. Instead of taking one input (a ratio: rise/run), it takes two inputs, a rise and a run. This prevents dividing by zero (for vertical lines) and signs of rise and run cancelling. The first input is the rise, and the second is the run. The output is the angle between the vector with those coordinates and the x-axis. So atan2() will give you some angle between -pi and pi.
Now let's look at what you have put into the atan2() function:
atan2(mouseY - height / 2, mouseX - width / 2);
So the vector you're considering is the vector from the middle of the canvas to the mouse. If this is what you want, great. If it's not, maybe consider
atan2(mouseY - player1.y, mouseX - player1.y);
which yields the "heading" (not really the heading) of the vector from the player's position to the mouse.
There are a couple of other potential problems (I can't figure out which one it is because p5.play isn't behaving, or I'm doing something else wrong):
radians/degrees: sometimes this stuff goes wrong. Try printing a and seeing if it's what you're looking for. If it's in degrees, consider saying player1.rotation = radians(a) instead. I know that p5.Vector.fromAngle() doesn't care about angleMode, maybe sprite.rotation doesn't either?
I don't know how drawSprites works, but you might consider putting it inside of the push()/pop() section. When drawing other shapes, this is how you get a rotation about the point (x, y):
let x = 100;
let y = 200;
let a = atan2(mouseY - y, mouseX - x);
push();
translate(x, y);
rotate(a);
square(-10, -10, 20);
pop();
The square is centered at (x,y), and is rotated about (x,y) toward the cursor. It's necessary that you do it in this order: push, translate, rotate, shape, pop. If you mix up that order, it doesn't do it right. But what you have is push, translate, pop, shape. I don't know how sprite.rotate works, so maybe it's supposed to do what you want. But here is another way to do a rotation. (If you're going to do it this way, I think you'd have to draw player1 "at (0,0)" after the translation and rotation, before pop)
I hope this helped!

How to rotate one object at another (slowly)

I have been looking around for this function and thus far I just can't find any I can make any sense of. I already have a rotating function to make it equal to the position but slowly is proving to be a bit harder with 0-360 and all.
I am using a html canvas 2d context to render the objects on a Cartesian coordinate system .
I would like object1 to face at positionX and positionY at a turn rate (R) , fairly straightforward.
there is no need for me to supply any code since your likely going to make your own anyways. But I will anyways here you go:
let faceAt = function (thisObject,positionX,positionY) {
let desiredLocationX = positionX - thisObject.transform.x;
let desiredLocationY = positionY -thisObject.transform.y;
thisObject.transform.rotation = Math.degrees(Math.atan2(desiredLocationY, desiredLocationX));
};
The (Math.degrees) function converts radians to degrees.
This thread says it all : https://www.google.ca/amp/s/jibransyed.wordpress.com/2013/09/05/game-maker-gradually-rotating-an-object-towards-a-target/amp/
This question is quite unclear. But, I'm assuming you essentially just want to rotate an element around an arbitrary point on a HTML5 canvas.
On a canvas, you can only draw one element at a time. You can't really manipulate singular elements - for example, you can't rotate an element by itself. Instead, you'd need to rotate the entire canvas. This will always rotate around the centre of the canvas, but if you move the canvas origin, then you will draw on a different part of the canvas; thus allowing you to rotate around a point.
Check out the following example. You can click anywhere on the canvas to make the square rotate around that point. Hopefully this is what you are after:
let cv = document.getElementById("cv");
let ctx = cv.getContext("2d");
let angle = 0;
//Variables you can change:
let speed = 1; //Degrees to rotate per frame
let pointX = 250; //The x-coord to rotate around
let pointY = 250; //The y-coord to rotate around
ctx.fillStyle = "#000";
setInterval(()=>{ //This code runs every 40ms; so that the animation looks smooth
angle = (angle + speed) % 360; //Increment the angle. Bigger changes here mean that the element will rotate faster. If we go over 360deg, reset back to 0.
ctx.clearRect(0, 0, 400, 400); //Clear away the previous frame.
//Draw the point we are rotating around
ctx.beginPath();
ctx.arc(pointX,pointY,5,0,2*Math.PI);
ctx.fill();
ctx.closePath();
ctx.save(); //Save the state before we transform and rotate the canvas; so we can go back to the unrotated canvas for the next frame
ctx.translate(pointX, pointY); //Move the origin (0, 0) point of the canvas to the point to rotate around. The canvas always rotates around the origin; so this will allow us to rotate around that point
ctx.rotate(angle*Math.PI/180); //Rotate the canvas by the current angle. You can use your Math.degrees function to convert between rads / degs here.
ctx.fillStyle = "#f00"; //Draw in red. This is also restored when ctx.restore() is called; hence the point will always be black; and the square will always be red.
ctx.fillRect(0, 0, 50, 50); //Draw the item we want rotated. You can draw anything here; I just draw a square.
ctx.restore(); //Restore the canvas state
}, 40);
//Boring event handler stuff
//Move the point to where the user clicked
//Not too robust; relys on the body padding not changing
//Really just for the demo
cv.addEventListener("click", (event)=>{
pointX = event.clientX - 10;
pointY = event.clientY - 10;
});
#cv {
border:solid 1px #000; /*Just so we can see the bounds of the canvas*/
padding:0;
margin:0;
}
body {
padding:10px;
margin:0;
}
<canvas id="cv" width="400" height="400"></canvas><br>
Click on the canvas above to make the rectangle rotate around the point that was clicked.

Moving object from A to B smoothly across canvas

I am trying to move an object smoothly from point A to point B using HTML canvas and regular javascript.
Point A is a set of coordinates
Point B is in the case the cursor location.
I made a jsfiddle of what I have so far: https://jsfiddle.net/as9fhmw8/
while(projectile.mouseX > projectile.x && projectile.mouseY < projectile.y)
{
ctx.save();
ctx.beginPath();
ctx.translate(projectile.x, projectile.y);
ctx.arc(0,0,5,0,2*Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
ctx.stroke();
ctx.restore();
if(projectile.mouseX > projectile.x && projectile.mouseY < projectile.y)
{
var stepsize = (projectile.mouseX - projectile.x) / (projectile.y - projectile.mouseY);
projectile.x += (stepsize + 1);
}
if(projectile.mouseY < projectile.y)
{
var stepsize = (projectile.y - projectile.mouseY) / (projectile.mouseX - projectile.x);
projectile.y -= (stepsize + 1);
}
}
Essentially what I can't figure out to do is to make the while loop slower (so that it appears animated in stead of just going through every iteration and showing the result).
I also can't figure out how to prevent the Arc from duplicating so that it creates a line that is permanent, instead of appearing to move from point a to point b.
Smooth animation here is really about determining how far to move your object for each iteration of the loop.
There is a little math involved here, but it's not too bad.
Velocity
Velocity in your case is just the speed at which your particles travel in any given direction over a period of time. If you want your particle to travel 200px over the course of 4 seconds, then the velocity would be 50px / second.
With this information, you can easily determine how many pixels to move (animate) a particle given some arbitrary length of time.
pixels = pixelsPerSecond * seconds
This is great to know how many pixels to move, but doesn't translate into individual X and Y coordinates. That's where vectors come in.
Vectors
A vector in mathematics is a measurement of both direction and magnitude. For our purposes, it's like combining our velocity with an angle (47°).
One of the great properties of vectors is it can be broken down into it's individual X and Y components (for 2-Dimensional space).
So if we wanted to move our particle at 50px / second at a 47° angle, we could calculate a vector for that like so:
function Vector(magnitude, angle){
var angleRadians = (angle * Math.PI) / 180;
this.magnitudeX = magnitude * Math.cos(angleRadians);
this.magnitudeY = magnitude * Math.sin(angleRadians);
}
var moveVector = new Vector(50, 47);
The wonderful thing about this is that these values can simply be added to any set of X and Y coordinates to move them based on your velocity calculation.
Mouse Move Vector
Modeling your objects in this way has the added benefit of making things nice and mathematically consistent. The distance between your particle and the mouse is just another vector.
We can back calculate both the distance and angle using a little bit more math. Remember that guy Pythagoras? Turns out he was pretty smart.
function distanceAndAngleBetweenTwoPoints(x1, y1, x2, y2){
var x = x2 - x1,
y = y2 - y1;
return {
// x^2 + y^2 = r^2
distance: Math.sqrt(x * x + y * y),
// convert from radians to degrees
angle: Math.atan2(y, x) * 180 / Math.PI
}
}
var mouseCoords = getMouseCoords();
var data = distanceAndAngleBetweenTwoPoints(particle.x, particle.y, mouse.x, mouse.y);
//Spread movement out over three seconds
var velocity = data.distance / 3;
var toMouseVector = new Vector(velocity, data.angle);
Smoothly Animating
Animating your stuff around the screen in a way that isn't jerky means doing the following:
Run your animation loop as fast as possible
Determine how much time has passed since last time
Move each item based on elapsed time.
Re-paint the screen
For the animation loop, I would use the requestAnimationFrame API instead of setInterval as it will have better overall performance.
Clearing The Screen
Also when you re-paint the screen, just draw a big rectangle over the entire thing in whatever background color you want before re-drawing your items.
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
Putting It All Together
Here is a Fiddle demonstrating all these techniques: https://jsfiddle.net/jwcarroll/2r69j1ok/3/

Canvas water/blob physics on a circular path with texture?

this is my first question after having relied on this site for years!
Anyway, I'd like to accomplish something similar to this effect:
http://www.flashmonkey.co.uk/html5/wave-physics/
But on a circular path, instead of a horizon. Essentially, a floating circle/blob in the center of the screen that would react to mouse interaction. What I'm not looking for is gravity, or for the circle to bounce around the screen - only surface ripples.
If at all possible I'd like to apply a static texture to the shape, is this a possibility? I'm completely new to Canvas!
I've already tried replacing some code from the above example with circular code from the following link, to very limited success:
http://www.html5canvastutorials.com/tutorials/html5-canvas-circles/
If only it were that easy :)
Any ideas?
Thanks in advance!
I tried to figure out how wave simulation works using View Source and JavaScript console. It's working fine but threw some JS errors. Also, it seems physics update is entangled with rendering in the render() method.
Here is what I found about the code:
The mouseMove() method creates disturbances on the wave based on mouse position, creating a peak around the mouse. The target variable is the index of the particle that needs to be updated, it's calculated from mouse pos.
if (particle && mouseY > particle.y) {
var speed = mouseY - storeY;
particles[target - 2].vy = speed / 6;
particles[target - 1].vy = speed / 5;
particles[target].vy = speed / 3;
particles[target + 1].vy = speed / 5;
particles[target + 2].vy = speed / 6;
storeY = mouseY;
}
Then, the particles around target are updated. The problem I found is that it does no bounds checking, i.e. it can potentially particles[-1] when target == 0. If that happens, an exception is thrown, the method call ends, but the code does not stop.
The render() method first updates the particle positions, then renders the wave.
Here is its physics code:
for (var u = particles.length - 1; u >= 0; --u) {
var fExtensionY = 0;
var fForceY = 0;
if (u > 0) {
fExtensionY = particles[u - 1].y - particles[u].y - springs[u - 1].iLengthY;
fForceY += -fK * fExtensionY;
}
if (u < particles.length - 1) {
fExtensionY = particles[u].y - particles[u + 1].y - springs[u].iLengthY;
fForceY += fK * fExtensionY;
}
fExtensionY = particles[u].y - particles[u].origY;
fForceY += fK / 15 * fExtensionY;
particles[u].ay = -fForceY / particles[u].mass;
particles[u].vy += particles[u].ay;
particles[u].ypos += particles[u].vy;
particles[u].vy /= 1.04;
}
Basically, it's Hooke's Law for a chain of particles linked by springs between them. For each particle u, it adds the attraction to the previous and next particles (the if statements check if they are available), to the variable fForceY. I don't fully understand the purpose of the springs array.
In the last four lines, it calculates the acceleration (force / mass), updates the velocity (add acceleration), then position (add velocity), and finally, reduce velocity by 1.04 (friction).
After the physics update, the code renders the wave:
context.clearRect(0, 0, stageWidth, stageHeight);
context.fillStyle = color;
context.beginPath();
for (u = 0; u < particles.length; u++) {
...
}
...
context.closePath();
context.fill();
I'm not explaining that, you need to read a canvas tutorial to understand it.
Here are some ideas to get started, note that I didn't test these code.
To modify the code to draw a circular wave, we need introduce a polar coordinate system, where the particle's x-position is the angle in the circle and y-position the distance from center. We should use theta and r here but it requires a large amount of refactoring. We will talk about transforming later.
mouseMove(): Compute particle index from mouse position on screen to polar coordinates, and make sure the disturbance wrap around:
Define the function (outside mouseMove(), we need this again later)
function wrapAround(i, a) { return (i + a.length) % a.length; }
Then change
particles[target - 2] --> particles[wrapAround(target - 2, particles)]
particles[target - 1] --> particles[wrapAround(target - 1, particles)]
...
The modulo operator does the job but I added particles.length so I don't modulo a negative number.
render(): Make sure the force calculation wrap around, so we need to wrapAround function again. We can strip away the two if statements:
fExtensionY = particles[wrapAround(u - 1, particles)].y - particles[u].y - springs[wrapAround(u - 1, springs)].iLengthY;
fForceY += -fK * fExtensionY;
fExtensionY = particles[u].y - particles[wrapAround(u + 1, particles)].y - springs[warpAround(u, springs)].iLengthY;
fForceY += fK * fExtensionY;
Here is the result so far in jsfiddle: Notice the wave propagate from the other side. http://jsfiddle.net/DM68M/
After that's done, the hardest part is rendering them on a circle. To do that, we need coordinate transform functions that treat particle's (x, y) as (angle in the circle, distance from center), and we also need inverse transforms for mouse interaction in mouseMove().
function particleCoordsToScreenCoords(particleX, particleY) {
return [ radiusFactor * particleY * Math.cos(particleX / angleFactor),
radiusFactor * particleY * Math.sin(particleX / angleFactor) ];
}
function screenCoordsToParticleCoords(screenX, screenY) {
// something involving Math.atan2 and Math.sqrt
}
Where the ...Factor variables needed to be determined separately. The angleFactor is two pi over the highest x-position found among particles array
Then, in the coordinates supplied to the context.lineTo, context.arc, use the particleCoordsToScreenCoords to transform the coordinates.

Draw arc with increasing radius?

I am drawing an arc which increases gradually and turns in to a circle.On completion of animation(arc turning in to a circle) i want to draw another circle with increased radius with the previous circle persisting and the second animation continuing.
Arc to circle fiddle
After the circle is drawn,it gets washed out which is something that I dont want and continue the second animation.
Some unnecessary animation appears after the completion.
What should I do?
MyCode:
setInterval(function(){
context.save();
context.clearRect(0,0,500,400);
context.beginPath();
increase_end_angle=increase_end_angle+11/500;
dynamic_end_angle=end_angle+increase_end_angle;
context.arc(x,y,radius,start_angle,dynamic_end_angle,false);
context.lineWidth=6;
context.lineCap = "round";
context.stroke();
context.restore();
if(dynamic_end_angle>3.5*Math.PI){ //condition for if circle completion
draw(radius+10);//draw from same origin and increasd radius
}
},66);
window.onload=draw(30);
UPDATE:when should i clear the interval to save some cpu cycles and why does the animation slows down on third circle ??
First of all, about the flicker: you are using setInterval and not clearing it for the next draw(). So there’s that.
But I’d use a completely different approach; just check the time elapsed since the start, and draw an appropriate number of circles using a loop.
var start = new Date().getTime();
var timePerCircle = 2;
var x = 190, y = 140;
function draw() {
requestAnimationFrame(draw);
g.clearRect(0, 0, canvas.width, canvas.height);
var t = (new Date().getTime() - start) / 1000;
var circles = t / timePerCircle;
var r = 30;
do {
g.beginPath();
g.arc(x, y, r, 0, Math.PI * 2 * Math.min(circles, 1));
g.stroke();
r += 10;
circles--;
} while(circles > 0);
}
draw();
This snippet from your code has some flaw.
if(dynamic_end_angle>3.5*Math.PI){ //condition for if circle completion
draw(radius+10);//draw from same origin and increased radius
}
The recursive call to draw() will continue to run after the first circle was drawn completely. This is why the performance will be slow down immediately. You need to somehow block it.
I did a simple fix, you can polish it if you like. FIDDLE DEMO
My fix is to remove context.clearRect(0, 0, 500, 400); and change the new circle drawing logic to:
if (dynamic_end_angle > 3.5 * Math.PI) { //condition for if circle completion
increase_end_angle = 0; // this will prevent the draw() from triggering multiple times.
draw(radius + 10); //draw from same origin.
}
In this stackoverflow thread, it mentions how to make it more smooth. You'd better use some drawing framework since the optimization needs a lot of work.
When should I clear the interval to save some cpu cycles?
Better yet not use an interval at all for a couple of reasons:
Intervals are unable to sync to monitor's VBLANK gap so you will get jerks from time to time.
If you use setInterval you risk stacking calls (not high risk in this case though).
A much better approach is as you probably already know to use requestAnimationFrame. It's less CPU hungry, is able to sync to monitor and uses less resources in general even less if current tab/window is not active.
Why does the animation slows down on third circle ??
Your drawing calls are accumulating which slows everything down (setInterval is not cleared).
Here is a different approach to this. It's a simplified way and uses differential painting.
ONLINE DEMO
The main draw function here takes two arguments, circle index and current angle for that circle. The circles radius are stored in an array:
...,
sa = 0, // start angle
ea = 359, // end angle
angle = sa, // current angle
oldAngle = sa, // old angle
steps = 2, // number of degrees per step
current = 0, // current circle index
circles = [70, 80, 90], // the circle radius
numOfCircles = circles.length, ...
The function stores the old angle and only draws a new segment between old angle and new angle with 0.5 added to compensate for glitches due to anti-alias, rounding errors etc.
function drawCircle(circle, angle) {
angle *= deg2rad; // here: convert to radians
/// draw arc from old angle to new angle
ctx.beginPath();
ctx.arc(0, 0, circles[circle], oldAngle, angle + 0.5);
ctx.stroke();
/// store angle as old angle for next round
oldAngle = angle;
}
The loop increases the angle, if above or equal to end angle it will reset the angle and increase the current circle counter. When current counter has reach last circle the loop ends:
function loop() {
angle += steps;
/// check angle and reset, move to next circle
if (angle >= ea - steps) {
current++;
angle = sa;
oldAngle = angle;
}
drawCircle(current, angle);
if (current < numOfCircles)
requestAnimationFrame(loop);
}

Categories