I am just starting trying to make some animation using HTML5 and JavaScript.
Currently I have created a JavaScript class for the ball. It has an update function which should update the position of the ball and a draw function which should draw it:
/*global Vector*/
var Ball = (function () {
function Ball(pPostion) {
this.setPosition(pPostion);
}
Ball.prototype.getPosition = function () {
return this.mPosition;
};
Ball.prototype.setPosition = function (pPosition) {
this.mPosition = pPosition;
};
Ball.prototype.draw = function (pContext) {
pContext.save();
pContext.beginPath();
pContext.arc(100, 100, 20, 0, Math.PI * 2, true);
pContext.closePath();
pContext.fillStyle = '#ff0000';
pContext.stroke();
pContext.restore();
};
Ball.prototype.update = function () {
this.getPosition().add(new Vector(10, 0));
};
return Ball;
}());
In the my main section I have created the following method:
function ballGameLoop() {
ball.draw(mainContext);
ball.update();
requestAnimationFrame(ballGameLoop);
}
And when called, it does draw the ball but it doesn't seem to move at all. I don't have a specific type of way I want the ball to be animated, just any kind of movement would be good. Can anyone give any advice on where I may be going wrong?
From the looks of it, it seems you are just drawing an arc at the same coordinates over and over again (center at (100,100)).
Incorporating your Ball's position into this would be the way to make the render location dependent on the object's position. From what it seems, something along the lines of the following would give movement:
Ball.prototype.draw = function (pContext) {
var coordinates = this.getPosition();
pContext.save();
pContext.beginPath();
pContext.arc(coordinates.X, coordinates.Y, 20, 0, Math.PI * 2, true);
pContext.closePath();
pContext.fillStyle = '#ff0000';
pContext.stroke();
pContext.restore();
};
I'm of course assuming on how you setup the Vector object, so I'm guessing x and y can be accessed by (Vector).X and (Vector).Y respectively.
anyway just my approach at it.
Related
var random = randomNumber(1, 7);
var Block = createSprite(200, 0);
var Blocks = createGroup();
Blocks.add(Block);
Blocks.setAnimationEach(random.toString());
createEdgeSprites();
function draw() {
background("white");
Move("down", 4, 1);
Move2("right", 4, 0, "left");
Move2("left", -4, 0, "right");
if (Blocks.isTouching(bottomEdge)) {
var Block = createSprite(200, 0);
Blocks.add(Block);
Blocks.setAnimationEach(randomNumber(1, 7).toString());
}
if (Blocks.isTouching(edges)) {
Blocks.collide(edges);
}
drawSprites();
}
function Move(Key, Velocity, Velocity2) {
if (keyDown(Key)) {
Block.velocityY = Velocity;
} else {
Block.velocityY = Velocity2;
}
}
function Move2(Key, Velocity, Velocity2, Key2) {
if (keyDown(Key)) {
Block.velocityX = Velocity;
} else if ((!keyDown(Key2))) {
Block.velocityX = Velocity2;
}
}
My issue is with
if (Blocks.isTouching(bottomEdge)) {
var Block = createSprite(200, 0);
Blocks.add(Block);
Blocks.setAnimationEach(randomNumber(1, 7).toString());
}
That code is basically for when a piece touches the ground, a new piece is made with a random Animation, that is the shape. I know I have to fix other stuff, but I know how to fix it. The thing I don't know how to do is set an animation once? Is there a code for that, because it constantly randomly changes the animation because the function draw() runs multiple times. But if I put it outside of that function, it only runs in the beginning of the program. Should I like push my sprite back up a little afterwards? I can't use const and I don't even know how to use it. Each time a sprite touches the ground, I want a new sprite to made and that animation is only set once. My biggest issue is that, I know there are other issues in that segment, but I can fix it myself
I'm trying out matter.js on p5.js.
I'm trying to make a simple Top Down simulation where bodies collide with each other when trying to move.
Here's my code:
let engine,world;
function setup() {
createCanvas(400, 400);
engine = Matter.Engine.create();
world = engine.world;
m1 = Matter.Bodies.rectangle(50,50,50,50);
m2 = Matter.Bodies.rectangle(100,50,50,50);
Matter.World.add(world,m1);
Matter.World.add(world,m2);
}
function draw() {
background(220);
Matter.Body.translate(m1,{x: 1,y: 0});
pos1 = m1.position;
pos2 = m2.position;
rectMode(CENTER);
rect(pos1.x,pos1.y,50,50);
rect(pos2.x,pos2.y,50,50);
}
My intention was to make body m1 push body m2 when trying to move in his direction. Unfortunately m1 is just going through m2. How do I make them collide?
I've seen that I can add stiffness to the body's options but I don't think that will help me if they are not colliding in the first place.
I just found the problem: the translate function won't ever check collisions. Instead I used the setVelocity function and updated the engine every frame.
Matter.Engine.update(engine);
Matter.Body.setVelocity(m1,v1);
I also had to turn off the gravity in the setup.
engine.world.gravity.y = 0;
I have been trying to make a JavaScript animation of moving circle in HTML Canvas without using global variables. I am using requestAnimationFrame function. Since JavaScript does not support passing variable by reference, I tried creating a Circle class:
class Circle{
constructor(x, y, dx, dy) //set initial position and velocity of circle
{
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
}
}
function moveCircle(circle, other variables)
{
//clear canvas
//calculate new position and velocity using circle.x, etc.
//save new values to the object
//draw new circle into the canvas
requestAnimationFrame(moveCircle);
}
function button()//function called after click on button
{
//initial settings of canvas, intial condition
circle = new Circle(x, y, dx, dy);
moveCircle(circle, other vars);
}
This makes one frame and then throws error "Cannot read property 'x' of undefined". What am I doing wrong? Is there any other way of doing this, while avoiding global variables?
First of all, you don't need to create a class you can just pass the coordinates in an object or as separate arguments.
Secondly you should use Function#bind on requestAnimationFrame to pass the same arguments to next call.
Example using object:
function moveCircle(circle) {
console.log(circle.x);
if (circle.x) {
circle.x -= circle.dx;
requestAnimationFrame(moveCircle.bind(null, circle));
}
}
function button() {
moveCircle({
x: 500,
y: 0,
dx: 20,
dy: 0
});
}
button();
Example without object:
function moveCircle(x, dx) {
console.log(x);
if (x) {
requestAnimationFrame(moveCircle.bind(null, x - dx, dx));
}
}
function button() {
moveCircle(500, 20);
}
button();
To keep things simple you could use a closure to create a handler that internally knows what your circle looks like and how it should move. A closure is simply a function that defines its own variables locally, then returns a function that can access those.
We want to return a function that only accepts one argument: time, since that is the argument passed into every handler in the AnimationFrame by the browser. Then we want the closure function to draw into the globally defined canvas. Have a look here:
const canvas = document.body.appendChild( document.createElement( 'canvas' ) );
function makeMovingCircle( canvas, x, y, radius, distance, duration ){
// Lets get the context to draw here so we only need to fetch it once and store it, saving some computing time in favour of storing into memory.
const ctx = canvas.getContext( '2d' );
// We need to return a named function here so it can interally call itself again in requestAnimationFrame
return function AnimationHandler( time ){
// Lets just calculate an offset here based on the distance and duration we passed in above.
const progress = (time % duration / duration) * distance;
ctx.clearRect( 0, 0, canvas.width, canvas.height );
ctx.beginPath();
ctx.arc( x + progress, y, radius, 0, Math.PI*2, true );
ctx.stroke();
// Now call the named handler for the next animationFrame
window.requestAnimationFrame( AnimationHandler );
}
}
// Now lets make an animation handler and add it to the animationFrame. If you ever want to cancel it, you might want to store it in a global variable though so you can call cancelAnimationFrame on it.
window.requestAnimationFrame(
makeMovingCircle( canvas, 15, 15, 10, 100, 2000 )
);
I did a quick example from my memory:
const circle = $('#circle');
class Main {
constructor() {
}
start() {
requestAnimationFrame(this.loop.bind(this))
}
loop() {
const pos = circle.position();
// speed is a constant 1,1. But you could replace it by a variable
circle.css({top: pos.top+1, left: pos.left+1, position:'absolute'});
requestAnimationFrame(this.loop.bind(this))
}
}
const main = new Main();
main.start();
<div>
<img id="circle" src="https://playcode.io/static/img/logo.png"
alt="PlayCode logo">
<h1 id="msg"></h1>
</div>
#circle {
position: absolute;
top: 0;
left: 0;
}
In js, object are passed by reference, and primitive types by value.
I think you should avoid having other variables in moveCircle function. That kind of function is usually called "loop" or "gameLoop" or "update". When your button is clicked, add a speed to the circle, without creating a new circle, something like myCircle.speed = {x:2, y:2}. In the gameloop, add the speed to the position each frame.
Think also about delta time, as requestAnimationFrame will be faster depending on the PC/Mobile that run it.
You can wrap your application into on Main class if you like. (like I did above)
Finnaly, if you insist passing parameters to moveCircle, you can use bind.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
function c(a,b,c) {
console.log(a); console.log(b); console.log(c);
}
c.bind(window, 4,3)
// function c() // bind will return a function ! In a class usually the context that you want to pass is `this`. If you are playing directly in the console, the context is window by default (not that it matter in this example)
c.bind(window, 4,3)()
// 4
// 3
// undefined
The first call to moveCircle (from what I understand, it is in button function), should also be a requestAnimationFrame like requestAnimationFrame(moveCircle.bind(window, other vars)), you could re-use that in moveCircle as well, to avoid any global variable. Still, I recommend making a class to wrap your application, so that you can use local variables to your class to save the current state of your game instead of having that same state living inside the function arguments only.
So i'm trying to rewrite some of main proccessing sketches to p5.js, but (there is always a but..) i have a problem with creating Vecotrs. I think i'm lacking some simple java script uderstanding here.
So i use the example provided with p5.js, and my code looks like that:
var location ;
function setup() {
createCanvas(1000, 1000);
background(0);
location = new Vector(0, 0);
//location = createVector(0, 0);
//location = new p5.Vector(0, 0);
}
function draw() {
ellipse(location.x, location.y, 80, 80);
}
function Vector (x,y) {
this.x = x;
this.y = x;
}
I tryied 3 ways of creating vectors, the one right now, with creating custom "class" Vector, and those 2 commented out. And if i try it out, i have page not found and address bar is changed to "address to my index.html/p5.Vector%20Object%20:%20[0,%200,%200]".
I really have now idea what is wrong.
The variable name was the culprit. I was actualy accessing window.location . Simple name change did the trick.
I am creating a simple drawing app using the HTML5 canvas element. The program logic works fine, and everything runs great, except for one thing.
When I draw the first line, the mouse coordinates and the line match perfectly. However, after each subsequent line, the coordinates of the line being drawn are about 0.5~1px off. These discrepancies accumulate, and the effect is readily visible after drawing about ten separate lines. This occurs in all browsers.
For a live example, check this fiddle. I have stripped down everything as much as I could. Obviously the real app is a lot more complex, but even in this simplified version the problem persists, which leads me to think I'm missing something incredibly obvious.
It occurred to me that I might be somehow rounding up the coordinates, which is about the only thing I can think of that could account for such a gradual drift. I was using a proprietary function for getting the offset values, so I tried using jQuery (since that has never given me problems in the past) but nothing changed.
Please help me figure out why this is happening!
Apparently I need to post code now in order to link to jsfiddle. I have no idea which part of the code might be wrong, so I apologise in advance for posting everything and creating a wall of text.
var offsetX = 0, offsetY = 0;
var currentMouseCoords = {
x : 0,
y : 0
};
var drawPing = null;
var ctx = null;
$('#cover').mousedown(function (event) {
event.preventDefault();
var f = $(this).offset();
offsetX = f.left;
offsetY = f.top;
currentMouseCoords.x = event.pageX - offsetX;
currentMouseCoords.y = event.pageY - offsetY;
drawStart();
if (!drawPing) {
drawPing = setInterval(draw, 10);
}
})
.mousemove(function (event) {
currentMouseCoords.x = event.pageX - offsetX;
currentMouseCoords.y = event.pageY - offsetY;
})
.mouseout(function (event) {
//When mouse leaves canvas, quit drawing
drawEnd();
})
.mouseup(function (event) {
//When mouse leaves canvas, quit drawing
drawEnd();
})
/* Functions that perform the actual drawing */
function drawStart () {
//Get canvas context
ctx = document.getElementById('canvas').getContext("2d");
ctx.translate(0.5,0.5);
//Set styles
ctx.strokeStyle = '#333333';
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.lineWidth = 1;
//Begin path
ctx.beginPath();
ctx.moveTo(
currentMouseCoords.x,
currentMouseCoords.y
);
}
function draw () {
ctx.lineTo(
currentMouseCoords.x,
currentMouseCoords.y
);
ctx.stroke();
}
function drawEnd () {
clearInterval(drawPing);
drawPing = null;
if (ctx) {
ctx.closePath();
ctx = null;
}
}
I imagine it'll make a lot more sense if you just look at the actual fiddle....
For the record, I googled for quite a while to see if anyone else had this issue, but either it's not that common or I can't find the right combination of words. There are myriad problems with mouse coordinates but none of them seem to be the same as the one I am experiencing.
You are repeatedly translating in your drawStart function and those translations are accumulating:
ctx.translate(0.5,0.5)
You can reverse the translate with translate(-.5,-.5) or wrap your drawing code in ctx.save()/ctx.restore().
You might also want to move your ctx=document... outside the drawStart "loop" for better performance.
//Get canvas context outside drawStart
ctx = document.getElementById('canvas').getContext("2d");