I'm trying to build a simple interaction where users input two numbers, have a gif loop a number of times equal to the sum of those numbers, and then have the gif freeze on the first frame (with an option to reset the process). I think I have figured out how to do almost all of this in p5, except for the gif looping.
Is there a way to control the loops of a gif in p5js? Is there a better way to approach this task? Animating a sprite or something would largely achieve the same goals if that was a wiser approach.
thank you!
let input, button, greeting;
function setup() {
// create canvas
createCanvas(710, 400);
//creates the first value input box
input1 = createInput();
input1.position(20, 65);
//creates the second value input box
input2 = createInput();
input2.position(200, 65);
//creates the 'go' button
go_button = createButton('calculate');
go_button.position(input2.x + input2.width, 65);
//pressing the button triggers the greet() function
go_button.mousePressed(greet);
//creates the reset button
reset_button = createButton('reset');
reset_button.position(20, height - 30);
//immediately hides it
reset_button.hide();
//press the button and reset the screen
reset_button.mousePressed(reset);
//initial text
greeting = createElement('h2', 'what numbers do you want to add?');
greeting.position(20, 5);
textAlign(CENTER);
textSize(50);
}
function greet() {
//hides the inputs and the go button
input1.hide();
input2.hide();
go_button.hide();
//does the math
const total = input1.value() + input2.value();
//updates the text
greeting.html('hello ' + total + '!');
//resets the input values for next time
input1.value('');
input2.value('');
//reveal the reset button
reset_button.show();
//just a thing to show the total
for (let i = 0; i < 200; i++) {
push();
fill(random(255), 255, 255);
translate(random(width), random(height));
rotate(random(2 * PI));
text(total, 0, 0);
pop();
}
}
function reset() {
//hides the old stuff
rect(-1,-1,width+5,height+5);
//shows the inputs and the go button
input1.show();
input2.show();
go_button.show();
//hides the reset button
reset_button.hide();
//updates the text
greeting.html('what numbers do you want to add?');
}
Related
I am making a game using JavaScript..
So, I want to display a "You Win!" text for 5 seconds.But when I execute it, It just shows the text for very less time and disappears.
{
//If Sofia touches the CUP then there should be a timeout for n seconds
textSize(30);
text("YOU WIN!!!", 200, 100);
sofia.x = 380;
sofia.y = 375;
}
Sofia is the Player's name and the CUP is just like a finish line for Sofia.
sofia.x = 380;
sofia.y = 375;
This piece of code is to put Sofia back to the initial position after it touches the Cup.
So, basically I want to display "You Win!" for some time (Say... 5 seconds).
You will display the message and after 5 seconds delete it.
document.getElementById("idOfBlock").innerText = msg;
setTimeout(function(){
document.getElementById("idOfBlock").innerText = '';
}, 5000);
I've been trying to figure out how to run an infinite loop while pausing for user click, then allow for a break out.
When the loop starts, the user is presented with an image, and must choose the identical image from one of 4 displayed. If they successfully click the match within 5 seconds, they are presented another image, and the game goes on.
If they either choose an incorrect image, or 5 seconds elapses, the game ends.
I've got all of the functionality worked out, except this pause while waiting for a click or the time to expire.
Ideally, I'd also like the time to be adjustable on each iteration. Say start at 5 seconds, then shorten the time slightly (10ms) on each loop.
I believe it must be solvable using setTimeout() or setInterval(), but just can't wrap my head around it.
Here is a minimal concept of what I'm trying to accomplish.
$('#playnow').on('click',function(){
var speed = 5000;
var speed_reduce = 10;
var game_running = true;
/* create array of images */
var imgs = ['puppy.png','kitten.png','bunny.png','goldfish.png'];
var runnow = setInterval(
function(){
//get random image from loaded theme
rand_img = imgs[Math.floor(Math.random() * imgs.length) ];
//display chosen image
$('#goal_image').html('<img src="'+theme_dir+rand_img+'" />');
// wait up to 5 seconds for user to click or time to expire
if(*clicked and matched*){
//get new random image and reset timer (less 10ms)
}
if(*time expired*){
//bail out and game ends
}
/* reduce time */
speed -= speed_reduce;
},
speed);
});
You'll want something like this I think:
var speed = 5000, // the initial time
currentimage,
timer,
gamerunning;
function newimage(){
var imgs = ['puppy.png','kitten.png','bunny.png','goldfish.png'];
currentimage=Math.floor(Math.random() * imgs.length);
$('#goal_image').html('<img src="'+theme_dir+imgs[currentimage]+'" />');
timer = setTimeout(speed, lost)
}
function answer(id){
if(!gamerunning){return}
clearTimeout(timer)
if(id==currentimage){
speed -= 10; // time decrease every time.
newimage();
}else{
lost()
}
}
function lost(){
gamerunning=0;
speed=5000;
// what to do when lost.
}
$("#puppy").on("click",function(){answer(0)}); // here #puppy is the id of the answer image, and 0 the index in the imgs array.
$("#kitten").on("click",function(){answer(1)});
$("#bunny").on("click",function(){answer(2)});
$("#fish").on("click",function(){answer(3)});
$("#gamestartbutton").on("click",function(){gamerunning=1})
One way to solve this problem is to use setTimeout() and clearTimeout() rather than setInterval. Also, you need some event for the successful button click (I've pretended you have a special "#successfulmatch" button):
var speed = 5000;
var speed_reduce = 10;
var game_running = true;
var imgs = ['puppy.png','kitten.png','bunny.png','goldfish.png'];
var myTimeout;
function runNow(speed){
rand_img = imgs[Math.floor(Math.random() * imgs.length) ];
$('#goal_image').html('<img src="'+theme_dir+rand_img+'" />');
// Keep track of the timeout so we can cancel it later if the user clicks fast enough.
myTimeout = window.setTimeout(function(){
game_running = false;
gameEnds();
},speed);
}
$('#successfulmatch').on('click',function(){
if(game_running){
// Cancel the timeout because the user was fast enough
window.clearTimeout(myTimeout);
// Give the user less time than before
runNow(speed - speed_reduce);
}
else{
// Throw an error: you forgot to hide the clickable buttons when the game ended.
}
}
$('#playnow').on('click',function(){
runNow(speed);
}
Looks like you are mixing the logic for checking "has the user clicked the image? was it correct?" with the one for checking "has time expired?"
You can listen for onclick events on the images
and set a timeout event for the game over
so the user has to cancel that timer, to cancel imminent game over, by clicking on the images
if the right image is clicked the timer is reset
if not, it's game over
you can cancel a timeout event before it runs with cancelTimeout()
see W3C here for a reference.
here is a quick prototype:
$('#playnow').on('click', function() {
var speed = 5000;
var speed_reduce = 10;
var game_running = true;
/* create array of images */
var imgs = ['puppy.png', 'kitten.png', 'bunny.png', 'goldfish.png'];
// function that ends the game if it's called
function gameover() {
alert("GAME OVER");
game_running = false;
}
// in order to use clearTimeout() you must store the timer in a global variable
// setting a timeout that will end the game if it's not cleared before
window.timer = setTimeout(gameover, speed);
// function that is called whenever the user clicks on a image
function onclickimage(event) {
if (!game_running) return;
if ( /*clicked right img*/ ) {
// get random image from loaded theme
var rand_img = imgs[Math.floor(Math.random() * imgs.length)];
// display chosen image
$('#goal_image').html('<img src="' + theme_dir + rand_img + '" />');
// delete timer, user now has one more opportunity
clearTimeout(timer);
// speed is less 10ms
speed -= speed_reduce;
// launch timer again
window.gametimer = setTimeout(loop, speed);
} else { // if click did not match correct image
gameover();
}
}
});
Well, firstly, you need to clearInterval() when they either click or fail in order to stop the current interval. Then, you can restart an interval with the new speed. The interval seems to be working for.
Every 5 seconds a new picture is displayed. So, you want an onclick event for the picture that clears the interval and starts a new one. So, you may want to use setTimeout instead of setInterval since it is only a single iteration at a time.
You could use setInterval, I suppose, but there's no real benefit to it. This way also makes it relatively easy to reduce the speed each time.
I'm new to programming and take Javascript as a school course. I have come upon this problem, and have been stuck because I have been unable to update the text; for instance, when I move my mouse over the canvas, it just overlaps the text. Is there any solution to updating text, or am I just missing something basic?
/* This program displays the x and y
* coordinates in a label on the screen
* and updates when the mouse moves */
function start(){
mouseMoveMethod(drawCoordinates);
}
function drawCoordinates(e){
var txt = new Text(e.getX(), "15pt Arial");
var text = new Text(e.getY(), "15pt Arial");
txt.setPosition(100, 100);
txt.setColor(Color.black);
add(txt);
text.setPosition(100, 200);
text.setColor(Color.black);
add(text);
}
The problem is that you're creating a new Text every time the drawCoordinates method executes.
If this was browser based, you'd need something like this...
function drawCoordinates(e){
//Check if we can find the lable for X first.
//If we can't, create a new one....
var txt = document.getElementById('txtX');
if(txt==null)
{
txt = new Text(e.getX(), "15pt Arial");
txt.setPosition(100, 100);
txt.setColor(Color.black);
add(txt);
}
else
txt.text = e.getX();
//and the same for Y
}
Hope that helps
I am using EaselJS and want to create a flashing color rectangle that will flash a certain number of times when a button is pressed, displaying random colors from an array. It should stop after 10 color flashes and then I want to extract the final color.
So far the relevant code I have is:
var colorArray = ["#FE7B62","#CB2DD3","#F1FD66","#004CE8","#FFD068", "#02A97E"];
square = new createjs.Shape();
square.graphics.beginFill("#000").drawRoundRect(850, 50, 100, 100, 20);
function pushButton(event) {
square.graphics.inject(animateColor);
}
function animateColor(event) {
this.fillStyle = colorArray[parseInt(Math.random()*6)];
}
This code successfully triggers the flashing of colors from my color array, but I am not sure what the best method of running the animation for a limited number of frames is. I tried pausing the ticker and restarting it on the onclick of the button but that failed. I also tried using a for loop in the pushButton function but that caused a "too much recursion error" in the browser. Here is my full file link https://github.com/RMehta95/sherman-land/blob/master/main.js.
I would suggest creating an event to trigger your action (xamountOfFrames). Here is a link to some information that might help
http://www.w3schools.com/tags/ref_eventattributes.asp
I ended up not using the inject function and instead redrawing the shape each time, creating a couple counter and timer variables to ensure that it looped through the proper amount of times.
function pushButton() {
if (timer === false) {
animate = setInterval(animateColor, 200);
timer = true;
}
}
function animateColor() {
square.graphics.clear();
displayColor = colorArray[Math.floor(Math.random()*colorArray.length)];
square.graphics.beginFill(displayColor).drawRoundRect(850, 50, 100, 100, 20);
counter++;
if (counter===15) {
clearInterval(animate);
counter=0;
movePlayer(displayColor);
timer = false;
return;
}
}
My problem is that when I am clicking on button, callfunction() method called and counter is incremented by 5, when I am again click counter incremented by 5 and displayed 10 on given location my problem is that when counter is incremented previous number is not erased and displayed incremented number on previous number. I want to remove previous number and display next incremented number. I have following code:
var count=0;
function callfunction()
{
context.fillText(count,200,200);
count = count+5;
//context.fillText("",200,200);
}
fillText with background colour, if it's monochromatic. Or preserve what was there before as image data, then paste it over later when you want to erase the text.
The only way i know is to clear the full canvas element using canvas.fillRect.
Please see this jsFiddle for an example.
count = 0;
function update(){
canvas.clearRect(0,0,canvas.width,canvas.height);
canvas.fillText(count,200,200);
//Draw anything else...
}
setInterval("update()",1000/60); //60 Frames per second
button.onclick = function(){ //Change button to your button element
count += 5;
}
This should work!
You can use clearRect() to just clear a portion of the canvas...
If you know the size of your text field, set clearRect() to a rectangle large enough to clear that text field:
var count=0;
function callfunction()
{
context.clearRect(200, 190, 50, 10); // clears a text field 50 x 10, above baseline
context.fillText(count,200,200);
count = count+5;
}
Try clearing the canvas first:
var count=0;
function callfunction()
{
context.clearRect ( 0 , 0 ,canvas.height , canvas.width );
context.fillText(count,200,200);
count = count+5;
//context.fillText("",200,200);
}