问题
I'm trying to shake an html element for my game.
I found this code here:
shake = function (sprite, magnitude = 16, angular = false) {
//A counter to count the number of shakes
var counter = 1;
//The total number of shakes (there will be 1 shake per frame)
var numberOfShakes = 10;
//Capture the sprite's position and angle so you can
//restore them after the shaking has finished
var startX = sprite.x,
startY = sprite.y,
startAngle = sprite.rotation;
// Divide the magnitude into 10 units so that you can
// reduce the amount of shake by 10 percent each frame
var magnitudeUnit = magnitude / numberOfShakes;
//The `randomInt` helper function
var randomInt = (min, max) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
//Add the sprite to the `shakingSprites` array if it
//isn't already there
if(shakingSprites.indexOf(sprite) === -1) {
//console.log("added")
shakingSprites.push(sprite);
//Add an `updateShake` method to the sprite.
//The `updateShake` method will be called each frame
//in the game loop. The shake effect type can be either
//up and down (x/y shaking) or angular (rotational shaking).
sprite.updateShake = () => {
if(angular) {
angularShake();
} else {
upAndDownShake();
}
};
}
//The `upAndDownShake` function
function upAndDownShake() {
//Shake the sprite while the `counter` is less than
//the `numberOfShakes`
if (counter < numberOfShakes) {
//Reset the sprite's position at the start of each shake
sprite.x = startX;
sprite.y = startY;
//Reduce the magnitude
magnitude -= magnitudeUnit;
//Randomly change the sprite's position
sprite.x += randomInt(-magnitude, magnitude);
sprite.y += randomInt(-magnitude, magnitude);
//Add 1 to the counter
counter += 1;
}
//When the shaking is finished, restore the sprite to its original
//position and remove it from the `shakingSprites` array
if (counter >= numberOfShakes) {
sprite.x = startX;
sprite.y = startY;
shakingSprites.splice(shakingSprites.indexOf(sprite), 1);
}
}
//The `angularShake` function
//First set the initial tilt angle to the right (+1)
var tiltAngle = 1;
function angularShake() {
if (counter < numberOfShakes) {
//Reset the sprite's rotation
sprite.rotation = startAngle;
//Reduce the magnitude
magnitude -= magnitudeUnit;
//Rotate the sprite left or right, depending on the direction,
//by an amount in radians that matches the magnitude
sprite.rotation = magnitude * tiltAngle;
counter += 1;
//Reverse the tilt angle so that the sprite is tilted
//in the opposite direction for the next shake
tiltAngle *= -1;
}
//When the shaking is finished, reset the sprite's angle and
//remove it from the `shakingSprites` array
if (counter >= numberOfShakes) {
sprite.rotation = startAngle;
shakingSprites.splice(shakingSprites.indexOf(sprite), 1);
//console.log("removed")
}
}
}
However it only works for canvas sprites. How can I get it to work with HTML elements? Thanks.
回答1:
I have adapted your function so that it works on DOM elements. It is a pretty hefty shake though, you might want to play with the parameters to damped it a little bit:
var shakingElements = [];
var shake = function (element, magnitude = 16, angular = false) {
//First set the initial tilt angle to the right (+1)
var tiltAngle = 1;
//A counter to count the number of shakes
var counter = 1;
//The total number of shakes (there will be 1 shake per frame)
var numberOfShakes = 15;
//Capture the element's position and angle so you can
//restore them after the shaking has finished
var startX = 0,
startY = 0,
startAngle = 0;
// Divide the magnitude into 10 units so that you can
// reduce the amount of shake by 10 percent each frame
var magnitudeUnit = magnitude / numberOfShakes;
//The `randomInt` helper function
var randomInt = (min, max) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
//Add the element to the `shakingElements` array if it
//isn't already there
if(shakingElements.indexOf(element) === -1) {
//console.log("added")
shakingElements.push(element);
//Add an `updateShake` method to the element.
//The `updateShake` method will be called each frame
//in the game loop. The shake effect type can be either
//up and down (x/y shaking) or angular (rotational shaking).
if(angular) {
angularShake();
} else {
upAndDownShake();
}
}
//The `upAndDownShake` function
function upAndDownShake() {
//Shake the element while the `counter` is less than
//the `numberOfShakes`
if (counter < numberOfShakes) {
//Reset the element's position at the start of each shake
element.style.transform = 'translate(' + startX + 'px, ' + startY + 'px)';
//Reduce the magnitude
magnitude -= magnitudeUnit;
//Randomly change the element's position
var randomX = randomInt(-magnitude, magnitude);
var randomY = randomInt(-magnitude, magnitude);
element.style.transform = 'translate(' + randomX + 'px, ' + randomY + 'px)';
//Add 1 to the counter
counter += 1;
requestAnimationFrame(upAndDownShake);
}
//When the shaking is finished, restore the element to its original
//position and remove it from the `shakingElements` array
if (counter >= numberOfShakes) {
element.style.transform = 'translate(' + startX + ', ' + startY + ')';
shakingElements.splice(shakingElements.indexOf(element), 1);
}
}
//The `angularShake` function
function angularShake() {
if (counter < numberOfShakes) {
console.log(tiltAngle);
//Reset the element's rotation
element.style.transform = 'rotate(' + startAngle + 'deg)';
//Reduce the magnitude
magnitude -= magnitudeUnit;
//Rotate the element left or right, depending on the direction,
//by an amount in radians that matches the magnitude
var angle = Number(magnitude * tiltAngle).toFixed(2);
console.log(angle);
element.style.transform = 'rotate(' + angle + 'deg)';
counter += 1;
//Reverse the tilt angle so that the element is tilted
//in the opposite direction for the next shake
tiltAngle *= -1;
requestAnimationFrame(angularShake);
}
//When the shaking is finished, reset the element's angle and
//remove it from the `shakingElements` array
if (counter >= numberOfShakes) {
element.style.transform = 'rotate(' + startAngle + 'deg)';
shakingElements.splice(shakingElements.indexOf(element), 1);
//console.log("removed")
}
}
};
DEMO
Have a look at the demo in the fiddle. The red
block is the regular upAndDownShake
, whereas the green
one uses angularShake
:
https://jsfiddle.net/12aueufy/1/
回答2:
You can use css animation like this example
@-webkit-keyframes shake {
0% { -webkit-transform: translate(2px, 1px) rotate(0deg); }
10% { -webkit-transform: translate(-1px, -2px) rotate(-1deg); }
20% { -webkit-transform: translate(-3px, 0px) rotate(1deg); }
30% { -webkit-transform: translate(0px, 2px) rotate(0deg); }
40% { -webkit-transform: translate(1px, -1px) rotate(1deg); }
50% { -webkit-transform: translate(-1px, 2px) rotate(-1deg); }
60% { -webkit-transform: translate(-3px, 1px) rotate(0deg); }
70% { -webkit-transform: translate(2px, 1px) rotate(-1deg); }
80% { -webkit-transform: translate(-1px, -1px) rotate(1deg); }
90% { -webkit-transform: translate(2px, 2px) rotate(0deg); }
100% { -webkit-transform: translate(1px, -2px) rotate(-1deg); }
}
.shake:hover {
-webkit-animation-name: shake;
-webkit-animation-duration: 0.5s;
-webkit-transform-origin:50% 50%;
-webkit-animation-iteration-count: infinite;
}
.shake {
display:inline-block
}
<div class="shake">Shake me</div>
<img class="shake" src="https://www.w3.org/2008/site/images/logo-w3c-screen-lg" />
To change speed of shaking, change values of animation-duration
, translate()
, rotate()
.
If you want to shake element using javascript see jsfiddle
回答3:
Maybe you should take a look in Animate.css, https://daneden.github.io/animate.css/, this is a css library that provides a lot of animations, including a shake one... I hope that this might work for your problem!
回答4:
function shake(e, oncomplete, distance, time) {
var time = 500;
var distance = 5;
var start = (new Date()).getTime();
animate();
function animate() {
var now = (new Date()).getTime();
// Get current time
var elapsed = now - start;
// How long since we started
var fraction = elapsed / time;
// What fraction of total time?
if (fraction < 1) {
var x = distance * Math.sin(fraction * 4 * Math.PI);
e.style.left = x + "px";
// We're aiming for a smooth 40 frames/second animation.
setTimeout(animate, Math.min(25, time - elapsed));
} else {
// Otherwise, the animation is complete
if (oncomplete) oncomplete(e);
// Invoke completion callback
}
}
}
function shakeme(event1) {
shake(event1.target);
}
document.getElementById("wood").addEventListener("mouseover", shakeme, false);
HTML Element
<button id="wood">Hello World</button>
Source
http://javascriipt.blogspot.com/2015/02/how-to-mimic-shake-animation-effect.html
回答5:
You could use some library for javascript animations like Velocity
It's really flexible and easy to use.
Please check this working sample, I'm pretty sure that you can create wished effect in minutes
Hope it help
来源:https://stackoverflow.com/questions/36962903/javascript-shake-html-element