How does the p5.js draw function work? - javascript

Can't work out what I'm doing wrong. Looking at the code below my logic is that each time the draw function is called the ellipse's coordinates are changed to be another random number.
However instead of the coordinates being changed, the ellipse is just being redrawn at the 'new' coordinates.
Does anyone care to shed some light on why the shape is being redrawn rather than moved? I'm using the p5 javascript library.
var frate = 10;
var elliX = 500;
var elliY = 400;
function setup() {
createCanvas(100, 100);
frameRate(frate);
}
function draw() {
elliX = (random(0,100));
elliY = (random(0,100));
ellipse(elliX, elliY, 30);
}

p5 doesn't clear the canvas by default, so it's adding a new circle every time you're drawing. To clear, you can call clear() beforehand, like so:
var frate = 10;
var elliX = 500;
var elliY = 400;
function setup() {
createCanvas(100, 100);
frameRate(frate);
}
function draw() {
clear();
elliX = (random(0,100));
elliY = (random(0,100));
ellipse(elliX, elliY, 30);
}
<script src="https://unpkg.com/p5#0.6.1/lib/p5.min.js"></script>

Related

Drawing objects on canvas created by eventlisteners()

I am new to JavaScript and I am having a hard time understanding how to get the canvas to cooperate with stuff I want to do.
I am trying to have my HTML button outside the canvas create a rectangle on the canvas. Then I want the rectangle to fall. I have the canvas animated, I have the button set to create a rectangle at user inputted coordinates, but...the canvas won't animate it.
It won't fall like the statically created rectangles. I also am struggling with how to get my button to create a new rectangle each time instead of redrawing the same one? Hoping someone can explain more than just give me the code.
Thanks in advance.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
window.onload = addListeners;
function addListeners() {
document.getElementById('b1').addEventListener('click',btn1,false);
function btn1() {
var inputx = document.getElementById("work").value;
var inputy = document.getElementById("y").value;
var inputs = document.getElementById("s").value;
new Rectangle(inputx,inputy,inputs);
// rec.x = inputx;
//rec.y = inputy;
//rec.s = inputs;
}
}
var r2 = new Rectangle(500, 50, 50);
var rec = new Rectangle();
//animate
function animate() {
requestAnimationFrame(animate);
ctx.clearRect(0,0,1450,250);
r2.draw();
r2.update();
rec.draw();
rec.update();
}
code for rectangle:
function Rectangle(x,y,s){
this.x = x;
this.y = y;
this.s = s;
this.draw = function(){
//console.log('fuck');
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect(this.x,this.y,this.s,this.s);
}
this.update = function(){
console.log(this.y);
if((this.y + this.s) <= 250){
this.y= this.y+2;
}
}
}
The button is not animating anything as the animate method was not being called. Also in your code when you called animate it ended in an infinite loop as requestAnimationFrame will continue to call animate repeatedly, so I've added a condition around requestAnimationFrame(animate) to check the squares height and stop running it when it reaches the bottom, similar to what you had in your update function.
To create a new square every time you click the button, I moved the creation of the Rectangles inside the btn1 function. If you want to keep the old squares while creating new ones, you will need to keep track of them outside the canvas and redraw them with everything else each animation.
I guessed what your html looks like, but you can run the code below it will drop two squares, but note that the stop condition is only on the hard coded one.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
document.getElementById("b1").addEventListener("click", btn1, false);
var r2;
var rec;
function btn1() {
var inputx = document.getElementById("work").value;
var inputy = document.getElementById("y").value;
var inputs = document.getElementById("s").value;
r2 = new Rectangle(500, 50, 50);
rec = new Rectangle(parseInt(inputx, 10), parseInt(inputy, 10), parseInt(inputs, 10));
animate();
}
//animate
function animate() {
if (r2.y + r2.s <= 400) {
requestAnimationFrame(animate);
}
ctx.clearRect(0,0,1450,400);
r2.draw();
r2.update();
rec.draw();
rec.update();
}
function Rectangle(x,y,s){
this.x = x;
this.y = y;
this.s = s;
this.draw = function(){
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect(this.x,this.y,this.s,this.s);
}
this.update = function(){
this.y= this.y+2;
}
}
<div>
<input id='work'>
<input id='y'>
<input id='s'>
<button id="b1"> Create Sqaure</button>
</div>
<canvas id="myCanvas" width=600 height=400></canvas>

Images not displaying the first time in this object program in JS

I am making a battleship game with polar coordinates. After the user chooses two points, a battleship should be drawn in the middle. My Battleship constructor looks like this:
function Battleship(size, location, source){
this.size = size;
//initializing the image
this.image = new Image();
this.image.src = source;
this.getMiddlePoint = function(){
//get midpoint of ship
...
}
this.distanceBetween = function(t1, t2){
//dist between two points
}
this.display = function(){
var point = [this.radius];
point.push(this.getMiddlePoint());
point = polarToReal(point[0], point[1] * Math.PI / 12);
//now point has canvas coordinates of midpoint
var width = this.distanceBetween(this.info[0][0], this.info[this.info.length-1][0]);
var ratio = this.image.width / width;
ctx.drawImage(this.image, point[0] - width/2, point[1] - this.image.height / ratio / 2, width, this.image.height / ratio);
//draws the image
}
}
The display method of each ship gets called at a certain point (after the user has chosen the location). For some reason, the images do not show the first time I do this, but when I run this code at the very end:
for(var i = 0; i<playerMap.ships.length; i++){
playerMap.ships[i].display();
}
All ships are displayed correctly (not aligned well, but they are displayed). I think there is a problem with loading the images. I am not sure how to fix this. I tried using image.onload but I never got that to work. I also tried something like this:
var loadImage = function (url, ctx) {
var img = new Image();
img.src = url
img.onload = function () {
ctx.drawImage(img, 0, 0);
}
}
but the same problem kept happening. Please help me fix this problem. Here is the game in its current condition. If you place ships, nothing happens, but after you place 5 (or 10) ships, they suddenly all load.
EDIT:
I solved the problem by globally defining the images. This is still very bad practice, since I wanted this to be in the battleship object. This is my (temporary) solution:
var sub = [];
for(var i = 1; i<5; i++){
sub[i] = new Image();
sub[i].src = "/img/ships/battleship_"+i+".png";
}

My Game loop accelerates and character leaves a trail

The code:
// create stuff
var ghObj = {
x : 0,
y : 0
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var ghost = new Image();
ghost.src = "ghost.png"
//define variables
var ghostMove = function () {
ghObj.x+=(Math.floor(Math.random() * 9 - 4))
console.log(ghObj.x)
ghObj.y+=(Math.floor(Math.random() * 9 - 4))
}
var ghostCheck = function () {
if (ghObj.x<0) {
ghObj.x=0
}
if (ghObj.x>390) {
ghObj.x=390
}
if (ghObj.y<0) {
ghObj.y=0
}
if (ghObj.y>390) {
ghObj.y=390
}
}
var drawIm = function (sprite, position) {
ctx.save();
ctx.translate(position.x, position.y);
ctx.drawImage(sprite, 0, 0, sprite.width, sprite.height, 0, 0, sprite.width, sprite.height);
ctx.restore();
};
// begin "game" when ghost is loaded
ghost.onload = function() {
mainLoop()
}
// main loop
function() {
ghostMove()
ghostCheck()
drawIm(ghost, ghObj)
setInterval(mainLoop, 1000)
}
sorry if its a bit long.
what's supposed to happen is the ghost moves randomly round the screen at a steady rate.
instead, it moves randomly but increasingly quickly and leaves copies of itself everywhere.
Isn't the restore function supposed to clear the screen each time?
have i got the game loop wrong?
thanks in advance.
function mainLoop(){
setInterval(mainLoop,100);
}
I think the error is obvious. I recommend to use setTimeout or requestAnimationFrame instead... And this should remove the duplicates i think its an optical ilusion
...

Flash cc + html 5: draw lines between moving objects

I'm an animator trying to branch into coding and I'm a bit stuck with fundamentals.
This is a simple character walk cycle, and I'm trying to draw the legs with code [arcTo] between the body [ManBody] and the feet [foot01].
The lines draw on and the body moves - but the lines are redrawn on EVERY frame - How/Where do I stage.update(); so that it's just a single line that draws on to the stage, and then moves between the moving parts?
//mouse cursor
stage.canvas.style.cursor = "none";
this.ManBody.mouseEnabled = false;
this.addEventListener("tick", fl_CustomMouseCursor.bind(this));
function fl_CustomMouseCursor() {
this.ManBody.x = (stage.mouseX+350) * 0.5 ;
this.ManBody.y = (stage.mouseY+200) * 0.5;
}
//line
createjs.Ticker.addEventListener("tick",fl_DrawLineCont.bind(this));
createjs.Ticker.setFPS(10);
function fl_DrawLineCont(event) {
var stroke_color = "#ff0000";
var shape = new createjs.Shape(new createjs.Graphics().beginStroke(stroke_color)
.moveTo(this.ManBody.x, this.ManBody.y)
.arcTo(this.foot01.x, this.foot01.y, this.ManBody.x, this.ManBody.y, 50).endStroke());
this.addChild(shape);
stage.update(event);
}
You creating shape every frame, you should create it outside of this and redraw it graphics like this:
var stroke_color = "#ff0000";
var graphics = new createjs.Graphics()
var shape = new createjs.Shape(graphics);
this.addChild(shape);
function fl_DrawLineCont(event)
{
graphics.clear();
graphics.beginStroke(stroke_color);
graphics.moveTo(this.ManBody.x, this.ManBody.y).arcTo(this.foot01.x, this.foot01.y, this.ManBody.x, this.ManBody.y, 50).endStroke();
stage.update(event);
}

HTML5 Canvas Drawing History

I'm curious to know how applications such as Adobe Photoshop implement their drawing history with the ability to go back or undo strokes on rasterized graphics without having to redraw each stroke from the beginning...
I'm wanting to implement a similar history function on an HTML5 drawing application I'm working on but duplicating the canvas after every stoke seems like it'd use too much memory to be a practical approach, especially on larger canvas'...
Any suggestions on how this might be implemented in a practical and efficient manner?
I may have a solution.....
var ctx = document.getElementById("canvasId").getContext("2d");
var DrawnSaves = new Array();
var Undo = new Array();
var FigureNumber = 0;
var deletingTimer;
function drawLine(startX, startY, destX, destY) {
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(destX, destY);
ctx.stroke();
var Para = new Array();
Para["type"] = "line";
Para["fromX"] = startX;
Para["fromY"] = startY;
Para["toX"] = destX;
Para["toY"] = destY;
DrawnSaves.push(Para);
FigureNumber++;
}
function undo() {
ctx.beginPath();
ctx.clearRect(0, 0, 500, 500);
Undo[FigureNumber] = DrawnSaves[FigureNumber];
DrawnSaves[FigureNumber] = "deleted";
FigureNumber--;
drawEverything();
startTimeoutOfDeleting();
}
function undoTheUndo() {
FigureNumber++;
DrawnSaves[FigureNumber] = Undo[FigureNumber];
drawEverything();
clearTimeout(deletingTimer);
}
function drawEverything() {
for (i = 0; i < DrawnSaves.length; i++) {
if (DrawnSaves[i].type == "line") {
ctx.beginPath();
ctx.moveTo(DrawnSaves[i].fromX, DrawnSaves[i].fromY);
ctx.lineTo(DrawnSaves[i].toX, DrawnSaves[i].toY);
ctx.stroke();
}
}
}
function startTimeoutOfDeleting() {
setTimeout(function() {Undo[FigureNumber] = "deleted";}, 5000);
}
This is really simple, first I draw a line when the function is called and save all his parameters in an array. Then , in the undo function I just start a timer do delete the figure drawn i 2000 miliseconds, clears the whole canvas and makes it can't be redrawn. in the undoTheUndo function, it stops the timer to delete the figure and makes that the figure can be redrawn. In the drawEverything function, it draws everything in the array based on it's type ("line here"). That's it... :-)
Here is an example working : This, after 2sec UNDOs then after 1sec UNDOTHEUNDO

Categories