Reputation: 255
I'm creating a platformer game in javascript in which players are rectangles and they can jump on and off platforms. This is pretty straightforward but now I'm trying to add a 'gelatine effect' to the players so that when they land on a platform they move a bit(like a gelatine). I've been searching for quite some time now but I can't seem to find any good examples on how I can change the shape of a rectangle.
All I've come up with is by using @keyframes in css and i've tried implementing it, which works if I use it on html elements. This is because with the DOM elements I can access the CSSStyleDeclaration with .style but if I create a new player object I can't(as seen in my code below).
I'm not sure how I can convert the css @keyframes to javascript or if what i'm doing isn't possible.. or if there perhaps are other (better) ways to achieve my goal?
var keystate = [];
var players = [];
var jelly = document.getElementById('jelly');
console.log(jelly.style); // shows the CSSStyleDeclarations
document.body.addEventListener("keydown", function(e) {
keystate[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keystate[e.keyCode] = false;
});
function gelatine(e) {
if (e.style.webkitAnimationName !== 'gelatine') {
e.style.webkitAnimationName = 'gelatine';
e.style.webkitAnimationDuration = '0.5s';
e.style.display = 'inline-block';
setTimeout(function() {
e.style.webkitAnimationName = '';
}, 1000);
}
}
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 300;
function Player(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.jumping = false;
this.velocityY = 0;
this.gravity = 0.3;
this.speed = 5;
this.timer = 0;
this.delay = 120;
}
Player.prototype.render = function render() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = 'blue';
context.fillRect(this.x, this.y, this.width, this.height);
context.fillStyle = 'black';
context.font = '20pt sans-serif';
context.fillText("I'm not jelly:(", this.x - 160, this.y + 30);
};
Player.prototype.update = function update() {
// arrow up key to jump with the player
if (keystate[38]) {
if (!this.jumping) {
this.jumping = true;
this.velocityY = -this.speed * 2;
}
}
this.velocityY += this.gravity;
this.y += this.velocityY;
if (this.y >= canvas.height - this.height) {
this.y = canvas.height - this.height;
this.jumping = false;
}
if (this.timer === 0) {
gelatine(jelly);
this.timer = this.delay;
}
if (this.timer > 0 && this.timer <= this.delay) {
this.timer--;
}
};
players.push(new Player((canvas.width / 2) - 25, (canvas.height / 2), 50, 50));
console.log(players[0].style); // no CSSStyleDeclarations :(
function render() {
for (var i = 0; i < players.length; i++) {
players[i].render();
}
}
function update() {
for (var i = 0; i < players.length; i++) {
players[i].update();
}
}
function tick() {
update();
render();
requestAnimationFrame(tick);
}
tick();
<html>
<head>
<style>
#jelly {
position: absolute;
margin-left: auto;
margin-right: auto;
top: 80px;
bottom: 0;
left: 0;
right: 0;
display: inline-block;
width: 100px;
height: 100px;
background: blue;
}
p {
font-size: 20px;
color: white;
}
canvas {
border: 1px solid #000;
position: absolute;
margin: auto;
top: 20px;
bottom: 0;
left: 0;
right: 0;
}
@keyframes gelatine {
25% {
-webkit-transform: scale(0.9, 1.1);
transform: scale(0.9, 1.1);
}
50% {
-webkit-transform: scale(1.1, 0.9);
transform: scale(1.1, 0.9);
}
75% {
-webkit-transform: scale(0.95, 1.05);
transform: scale(0.95, 1.05);
}
}
</style>
<title>Jelly rectangle</title>
</head>
<body>
<div id="jelly">
<p>   i'm jelly :)</p>
</div>
<canvas id='canvas'></canvas>
</body>
</html>
Upvotes: 0
Views: 1272
Reputation: 54069
Jelly.
To create a jelly effect for using in a game we can take advantage of a step based effect that is open ended (ie the effect length is dependent on the environment and has no fixed time)
Jelly and most liquids have a property that they are incompressible. This means that no matter the force applied to them the volume does not change. For a 2D game this mean that for jelly the area does not change. This means we can squash the height and knowing the area calculate the width.
Thus when a object drops and hits the ground we can apply a squashing force to the object in the height direction. Simulating a dampened spring we can produce a very realistic jelly effect.
Defining the jelly
I am being a little silly as it is the season so the variables wobbla and bouncy define the dampened spring with wobbla
being the stiffness of the spring from 0 to 1, with 0.1 being very soft to 1 being very stiff. Bouncy being the damping of the spring from 0 to 1, with 0 having 100% damping and 1 having no damping.
I have also added react
which is a simple multiplier to the force applied to the spring. As this is a game there is a need to exaggerate effects. react
multiplies the force applied to the spring. Values under 1 reduce the effect, values over 1 increase the effect.
hr
and hd
(yes bad names) are the real height (displayed) and the height delta ( the change in height per frame). These two variable control the spring effect.
There is a flag to indicate that the jelly is on the ground and the sticky
flag if true keeps the jelly stuck to the ground.
There are also three functions to control the jelly
function createJellyBox(image,x, y, wobbla, bouncy, react){
return {
img:image,
x : x, // position
y : y,
dx : 0, // movement deltas
dy : 0,
w : image.width, // width
h : image.height, // height
area : image.width * image.height, // area
hr : image.height, // squashed height chaser
hd : 0, // squashed height delta
wobbla : wobbla, // higher values make it wobble more
bouncy : bouncy, // higher values make it react to change in speed
react : react, // additional reaction multiplier. < 1 reduces reaction > 1 increases reaction
onGround : false, // true if on the ground
sticky : true, // true to stick to the ground. false to let it bounce
squashed : 1, // the amount of squashing or stretching along the height
force : 0, // the force applied to the jelly when it hits the ground
draw : drawJelly, // draw function
update : updateJelly, // update function
reset : resetJelly, // reset function
}
}
The functions
There are three functions to control the jelly, reset, update and draw. Sorry the answer is over the 30000 character limit so find the functions in the demo below.
Draw
Draw simply draws the jelly. It uses the squashed value to calculate the height and from that calculates the width, then simply draws the image with the set width and height. The image is drawn at its center to keep calculations simpler.
Reset
Simply resets the jelly at a position defined by x
and y
you can modify it to remove any wobbles by setting jelly.hr = jelly.h
and jelly.hd = 0
Update
This is where the hard work is. It updates the object position by adding gravity to the delta Y. It checks if the jelly has hit the ground, if it has it applies the force to the jelly.hr
spring by adding to the jelly.hd
(height delta) the force equal to the speed of the inpact times jelly.react
I found that the force applied should be over time so there is a little cludge (marked with comments) to apply a squashing force over time. That can be removed but it just reduces the smoothness of the jelly wobbly effect.
Last thing is to recalculate the height and move the jelly so that it does not cross into the ground.
Clear as mud cake I am sure. So feel free anyone to ask questions if there is a need to clarify.
DEMO
What would any good SO answer be without a demo. So here is a jelly simulation. Click on the canvas to drop the jelly. The three sliders on the top left control the values Wobbla, Bouncy, and React. Play witht the values to change the jelly effect. The check box turn on and off sticky, but you need a long screen to get the impact you need to bounce up. Remove the cludge code to see sticky real purpose.
As I needed a UI there is a lot of extra code that does not apply to the answer. The Answer code is clearly marked so to be easy to find. The main loop is at the bottom. I have not yet tested it on FF but it should work. If not let me know and I will fix it.
var STOP = false; // stops the app
var jellyApp = function(){
/** Compiled by GROOVER Quick run 9:43pm DEC-22-2015 **/
/** fullScreenCanvas.js begin **/
var canvas = (function(){
var canvas = document.getElementById("canv");
if(canvas !== null){
document.body.removeChild(canvas);
}
// creates a blank image with 2d context
canvas = document.createElement("canvas");
canvas.id = "canv";
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.position = "absolute";
canvas.style.top = "0px";
canvas.style.left = "0px";
canvas.style.zIndex = 1000;
canvas.ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
return canvas;
})();
var ctx = canvas.ctx;
/** fullScreenCanvas.js end **/
/** MouseFull.js begin **/
var canvasMouseCallBack = undefined; // if needed
var mouse = (function(){
var mouse = {
x : 0, y : 0, w : 0, alt : false, shift : false, ctrl : false,
interfaceId : 0, buttonLastRaw : 0, buttonRaw : 0,
over : false, // mouse is over the element
bm : [1, 2, 4, 6, 5, 3], // masks for setting and clearing button raw bits;
getInterfaceId : function () { return this.interfaceId++; }, // For UI functions
startMouse:undefined,
};
function mouseMove(e) {
var t = e.type, m = mouse;
m.x = e.offsetX; m.y = e.offsetY;
if (m.x === undefined) { m.x = e.clientX; m.y = e.clientY; }
m.alt = e.altKey;m.shift = e.shiftKey;m.ctrl = e.ctrlKey;
if (t === "mousedown") { m.buttonRaw |= m.bm[e.which-1];
} else if (t === "mouseup") { m.buttonRaw &= m.bm[e.which + 2];
} else if (t === "mouseout") { m.buttonRaw = 0; m.over = false;
} else if (t === "mouseover") { m.over = true;
} else if (t === "mousewheel") { m.w = e.wheelDelta;
} else if (t === "DOMMouseScroll") { m.w = -e.detail;}
if (canvasMouseCallBack) { canvasMouseCallBack(m.x, m.y); }
e.preventDefault();
}
function startMouse(element){
if(element === undefined){
element = document;
}
"mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",").forEach(
function(n){element.addEventListener(n, mouseMove);});
}
mouse.mouseStart = startMouse;
return mouse;
})();
if(typeof canvas === "undefined"){
mouse.mouseStart(canvas);
}else{
mouse.mouseStart();
}
/** MouseFull.js end **/
// unit size for rendering scale
var ep = canvas.height / 72;
// font constants
const FONT = "px Arial Black";
const FONT_SIZE = Math.ceil(3 * ep);
const GRAVITY = ep * (1/5);
const GROUND_AT = canvas.height - canvas.height * (1/20);
// Answer code.
//----------------------------------------------------------------------- // draw the jelly
function drawJelly(ctx){
var w,h;
w = this.w,
h = this.h;
h *= this.squashed;
// the width is ajusted so that the area of the rectagle remains constant
w = this.area / h; // to keep the area constant
ctx.drawImage(this.img,this.x - w / 2, this.y - h / 2, w, h);
}
function resetJelly(x,y){ // reset the jelly position
this.x = x;
this.y = y;
this.onGround = false;
this.dx = 0;
this.dy = 0;
}
// do the jelly math
function updateJelly(){
var h; // temp height
var hitG = false; // flag that the ground has just been hit
h = this.h * this.squashed; // get the height from squashed
if(!this.onGround){ // if not on the ground add grav
this.dy += GRAVITY;
}else{ // if on the ground move it so it touches correctly
this.dy = 0;
this.y = GROUND_AT - h / 2;
}
// update the position
this.x += this.dx;
this.y += this.dy;
// check if it has hit the ground
if(this.y + h / 2 >= GROUND_AT && this.dy >= 0){
this.hd += this.dy * this.react; // add the hit speed to the height delta
// multiply with react to inhance or reduce effect
this.force += this.dy * this.react;
hitG = true;
this.onGround = true; // flag that jelly is on the ground
}
if(this.force > 0){
this.hd += this.force;
this.force *= this.wobbla;
}
this.hd += (this.h - this.hr) * this.wobbla; // add wobbla to delta height
this.hd *= this.bouncy; // reduce bounce
this.hr += this.hd; // set the real height
this.squashed = this.h / this.hr; // calculate the new squashed amount
h = this.h * this.squashed; // recalculate hieght to make sure
// the jelly does not overlap the ground
// do the finnal position ajustment to avoid overlapping the ground
if(this.y + h / 2 >= GROUND_AT || hitG || (this.sticky && this.onGround)){
this.y = GROUND_AT - h / 2;
}
}
// create a jelly box
function createJellyBox(image,x, y, wobbla, bouncy, react){
return {
img:image,
x : x, // position
y : y,
dx : 0, // movement deltas
dy : 0,
w : image.width, // width
h : image.height, // height
area : image.width * image.height, // area
hr : image.height, // squashed height chaser
hd : 0, // squashed height delta
wobbla : wobbla, // higher values make it wobble more
bouncy : bouncy, // higher values make it react to change in speed
react : react, // additional reaction multiplier. < 1 reduces reaction > 1 increases reaction
onGround : false, // true if on the ground
sticky : true, // true to stick to the groun. false to let it bounce
squashed : 1, // the amount of squashing or streaching along the height
force : 0,
draw : drawJelly, // draw function
update : updateJelly, // update function
reset : resetJelly, // reset function
}
}
// --------------------------------------------------------------------------------------------
// END OF ANSWER CODE.
// FIND the usage at the bottom inside the main loop function.
// --------------------------------------------------------------------------------------------
// The following code is just helpers and UI stuff and are not related to the answer.
var createImage = function (w, h ){
var image = document.createElement("canvas");
image.width = w;
image.height = h;
image.ctx = image.getContext("2d");
return image;
}
var drawSky = function (img, col1, col2){
var c, w, h;
c = img.ctx;
w = img.width;
h = img.height;
var g = c.createRadialGradient(w * (1 / 2), h * (3 / 2), h * (1 / 2) +w * (1 / 4), w * (1 / 2), h * (3 / 2), h * (3 / 2) + w * ( 1 / 4));
g.addColorStop(0,col1);
g.addColorStop(1,col2);
c.fillStyle = g;
c.fillRect(0, 0, w, h);
return img;
}
var drawGround = function (img, col1, col2,lineColour, lineWidth) {
var c, w, h, lw;
c = img.ctx;
w = img.width;
h = img.height;
lw = lineWidth;
var g = c.createLinearGradient(0, 0, 0, h + lineWidth);
g.addColorStop(0, col1);
g.addColorStop(1, col2);
c.fillStyle = g;
c.lineWidth = lw;
c.strokeStyle = lineColour;
c.strokeRect(-lw * 2, lw / 2, w + lw * 4, h + lw * 4);
c.fillRect(-lw * 2, lw / 2, w + lw * 4, h + lw * 4);
return img;
}
/** CanvasUI.js begin **/
var drawRoundedBox = function (img, colour, rounding, lineColour, lineWidth) {
var c, x, y, w, h, r, p
p = Math.PI/2; // 90 deg
c = img.ctx;
w = img.width;
h = img.height;
lw = lineWidth;
r = rounding ;
c.lineWidth = lineWidth;
c.fillStyle = colour;
c.strokeStyle = lineColour;
c.beginPath();
c.arc(w - r - lw / 2, h - r - lw / 2, r, 0, p);
c.lineTo(r + lw / 2, h - lw / 2);
c.arc(r + lw / 2, h - r - lw / 2, r, p, p * 2);
c.lineTo(lw / 2, h - r - lw / 2);
c.arc(r + lw / 2, r + lw / 2, r, p * 2, p * 3);
c.lineTo(w-r - lw / 2, lw / 2);
c.arc(w - r - lw / 2, r + lw / 2, r, p * 3, p * 4);
c.closePath();
c.stroke();
c.fill();
return img;
}
var drawTick = function (img , col, lineColour, lineWidth){
var c, w, h, lw, m, l;
m = function (x, y) {c.moveTo(lw / 2 + w * x, lw / 2 + h * y);};
l = function (x, y) {c.lineTo(lw / 2 + w * x, lw / 2 + h * y);};
lw = lineWidth;
c = img.ctx;
w = img.width - lw;
h = img.height - lw;
c.fillStyle = col;
c.strokeStyle = lineColour;
c.lineWidth = lw;
c.beginPath();
m(1, 0);
l(5 / 8, 1);
l(0, 3 / 4);
l(1 / 4, 2 / 4);
l(2 / 4, 3 / 4);
l(1, 0);
c.stroke();
c.fill();
return img;
}
var setFont = function(ctx,font,align){
ctx.font = font;
ctx.textAlign = align;
}
var measureText = function(ctx,text){
return ctx.measureText(text).width;
}
var drawText = function(ctx,text,x,y,col,col1){
var of;
of = Math.floor(FONT_SIZE/10);
ctx.fillStyle = col1;
ctx.fillText(text,x+of,y+of);
ctx.fillStyle = col;
ctx.fillText(text,x,y);
}
var drawSlider = function(ctx){
var x,y;
x = this.owner.x;
y = this.owner.y;
ctx.drawImage(this.image, this.x + x, this.y + y);
ctx.drawImage(this.nob, this.nx + x, this.ny + y);
}
var updateSlider = function(mouse){
var mx, my;
mx = mouse.x - this.owner.x;
my = mouse.y - this.owner.y;
this.cursor = "";
if(this.owner.dragging === -1 || this.owner.dragging === this.id ){
if(mx >= this.x && mx < this.x + this.w &&
my >= this.y && my <= this.y + this.h){
this.mouseOver = true;
this.cursor = "pointer"
}else{
this.mouseOver = false;
}
if(mx >= this.nx && mx < this.nx + this.nw &&
my >= this.ny && my <= this.ny + this.nh){
this.mouseOverNob = true;
this.cursor = "ew-resize"
}else{
this.mouseOverNob = false;
}
if((mouse.buttonRaw&1) === 1 && (this.mouseOver||this.mouseOverNob) && !this.dragging){
this.owner.dragging = this.id;
this.dragging = true;
this.cursor = "ew-resize"
}else
if(this.dragging){
this.cursor = "ew-resize"
if((mouse.buttonRaw & 1)=== 0){
this.dragging = false;
this.owner.dragging = -1;
this.cursor = "pointer";
}
var p = mx- (this.x+this.nw/2);
p /= (this.w-this.nw);
p *= this.range;
p += this.min;
this.value = Math.min(this.max, Math.max(this.min, p));
}
if(this.mouseOver || this.mouseOverNob || this.dragging){
this.owner.toolTip = this.toolTip.replace("##",this.value.toFixed(this.decimals));
}
}
this.nx = (this.value - this.min) / this.range * (this.w - this.nw) + this.x;
}
var createSlider = function(image,nobImage, x, y, value, min, max, toolTip) {
var decimals = 0;
if(toolTip.indexOf("#.") > -1){
if(toolTip.indexOf(".DDD") > -1){
decimals = 3;
toolTip = toolTip.replace("#.DDD","##");
}else
if(toolTip.indexOf(".DD") > -1){
decimals = 2;
toolTip = toolTip.replace("#.DD","##");
}else
if(toolTip.indexOf(".D") > -1){
decimals = 1;
toolTip = toolTip.replace("#.D","##");
}else{
toolTip = toolTip.replace("#.","##");
}
}
return {
id : undefined,
image : image,
nob : nobImage,
min : min,
max : max,
x : x,
y : y + (nobImage.height - image.height)/2,
ny : y ,
nx : ((value - min) / (max - min)) * (image.width - nobImage.width) + x,
range : max - min,
w : image.width,
h : image.height,
nw : nobImage.width,
nh : nobImage.height,
value : value,
maxH : Math.max( image.height, nobImage.height),
mouseOver : false,
mouseOverNob : false,
toolTip:toolTip,
decimals:decimals,
dragging : false,
update : updateSlider,
draw : drawSlider,
position : function (x, y){
this.x += x;
this.y += y;
this.nx += x;
this.ny += y;
},
}
}
var drawTickCont = function(ctx){
var x,y, ofx, ofy;
x = this.owner.x;
y = this.owner.y;
ctx.drawImage(this.image, this.x + x, this.y + y);
ofy = this.h / 2 - this.textImage.height / 2;
ofx = this.w / 2;
ctx.drawImage(this.textImage, this.x + x + this.w + ofx, this.y + y + ofy);
if(this.value){
x -= this.tickImage.width * ( 1/ 4);
y -= this.tickImage.height * ( 2/ 5);
ctx.drawImage(this.tickImage, this.x + x, this.y + y);
}
}
var updateTick = function(mouse){
var mx, my;
mx = mouse.x - this.owner.x;
my = mouse.y - this.owner.y;
this.cursor = "";
if(this.owner.dragging === -1 || this.owner.dragging === this.id ){
if(mx >= this.x && mx < this.x + this.w &&
my >= this.y && my <= this.y + this.h){
this.mouseOver = true;
this.cursor = "pointer"
}else{
this.mouseOver = false;
}
if((mouse.buttonRaw&1) === 1 && this.mouseOver && !this.dragging){
this.owner.dragging = this.id;
this.dragging = true;
}else
if(this.dragging){
if((mouse.buttonRaw & 1)=== 0){
if(this.mouseOver){
this.value = ! this.value;
}
this.dragging = false;
this.owner.dragging = -1;
this.cursor = "pointer";
}
}
if(this.mouseOver || this.dragging){
this.owner.toolTip = this.toolTip;
}
}
}
var createTick= function(image,tickImage,textImage, x, y, value, toolTip) {
return {
id : undefined,
image : image,
tickImage : tickImage,
textImage : textImage,
x : x,
y : y,
w : image.width,
h : image.height,
value : value,
maxH : Math.max( image.height, tickImage.height),
mouseOver : false,
mouseOverNob : false,
toolTip:toolTip,
dragging : false,
update : updateTick,
draw : drawTickCont,
position : function (x, y){
this.x += x;
this.y += y;
},
}
}
function UI(ctx, mouse, x, y){
this.dragging = -1;
var ids = 0;
var controls = [];
var length = 0;
this.x = x;
this.y = y;
var posX = 0;
var posY = 0;
this.addControl = function (control, name) {
control.id = ids ++;
control.owner = this;
control.position(posX, posY);
posY += control.maxH + ep;
length = controls.push(control)
this[name] = control;
}
this.update = function(){
var i, cursor, c;
cursor = "";
this.toolTip = "";
for(i = 0; i < length; i ++){
c = controls[i];
c.update(mouse);
if(c.cursor !== ""){
cursor = c.cursor;
}
c.draw(ctx);
}
if(cursor === ""){
ctx.canvas.style.cursor = "default";
}else{
ctx.canvas.style.cursor = cursor;
}
if(this.toolTip !== ""){
if(mouse.y - FONT_SIZE * (5 / 3) < 0){
drawText(ctx, this.toolTip, mouse.x, mouse.y + FONT_SIZE * (4 / 3), "#FD4", "#000");
}else{
drawText(ctx, this.toolTip, mouse.x, mouse.y - FONT_SIZE * (2 / 3), "#FD4", "#000");
}
}
}
}
/** CanvasUI.js end **/
//-----------------------------
// create UI
//-----------------------------
setFont(ctx, FONT_SIZE + FONT, "left");
// images for UI
var tickBox = drawRoundedBox(createImage(4 * ep, 4 * ep), "#666", (3 / 2) * ep, "#000", (1 / 2) * ep);
var tickBoxTick = drawTick(createImage(6 * ep, 6 * ep), "#0D0", "#000", (1 / 2) * ep);
var w = measureText(ctx, "Sticky");
var tickBoxText = createImage(w, FONT_SIZE);
setFont(tickBoxText.ctx, FONT_SIZE + FONT, "left");
drawText(tickBoxText.ctx, "Sticky", 0, FONT_SIZE * (3 / 4), "white", "black");
var sliderBar = drawRoundedBox(createImage(20 * ep, 2 * ep), "#666", ep * 0.9, "#000", (1 / 2) * ep);
var sliderNob = drawRoundedBox(createImage(3 * ep, 4 * ep), "#AAA", ep, "#000", (1 / 2) * ep);
// UI control
var controls = new UI(ctx, mouse, 10, 10);
controls.addControl(createSlider(sliderBar, sliderNob, 0, 0, 0.3, 0, 1, "Wobbla #.DD"), "wobbla");
controls.addControl(createSlider(sliderBar, sliderNob, 0, 0, 0.8, 0, 1, "Bouncy #.DD"), "bouncy");
controls.addControl(createSlider(sliderBar, sliderNob, 0, 0, 1.5, 0, 2, "React #.DD"), "react");
controls.addControl(createTick(tickBox, tickBoxTick, tickBoxText, 0, 0, true, "Activate / Deactivate sticky option."), "sticky");
//-----------------------------
// create playfield
//-----------------------------
var skyImage = drawSky(createImage(32, 32), "#9EF", "#48D");
var groundImage = drawGround(createImage(100, canvas.height - GROUND_AT), "#5F5", "#5A5", "#181", 4);
//-----------------------------
// create jelly
//-----------------------------
var jellyImage = drawRoundedBox(createImage(ep * 20, ep * 20), "#FA4", ep * 2, "black", ep * (3 / 5));
var jelly = createJellyBox(
jellyImage,
canvas.width / 2,
100,
0.1,
0.8,
1.2
);
// some more settings
ctx.imageSmoothingEnabled = true;
setFont(ctx, FONT_SIZE + FONT, "left");
//-----------------------------
// Main animtion loop
//-----------------------------
function updateAnim(){
// draw the background and ground
ctx.drawImage(skyImage, 0, 0, canvas.width, canvas.height)
ctx.drawImage(groundImage, 0, GROUND_AT, canvas.width, canvas.height - GROUND_AT)
// update and draw jelly
jelly.update();
jelly.draw(ctx);
// update and draw controls
controls.update();
// update jelly setting from controls.
jelly.wobbla = controls.wobbla.value;
jelly.bouncy = controls.bouncy.value;
jelly.react = controls.react.value;
jelly.sticky = controls.sticky.value;
// if the mouse is not busy then use left mouse click and drag to position jellu
if(controls.dragging < 0 && mouse.buttonRaw === 1){
controls.dragging = -2;
jelly.reset(mouse.x,mouse.y);
}else
if(controls.dragging === -2){ // release mouse
controls.dragging = -1;
}
if(!STOP){
requestAnimationFrame(updateAnim);
}else{
STOP = false;
}
}
updateAnim();
};
function resizeEvent(){
var waitForStopped = function(){
if(!STOP){ // wait for stop to return to false
jellyApp();
return;
}
setTimeout(waitForStopped,200);
}
STOP = true;
setTimeout(waitForStopped,100);
}
window.addEventListener("resize",resizeEvent);
jellyApp();
Upvotes: 3