I am trying to do some game development project with p5.js. Its really simple. Essentially I need to be able to go ontop of an object on a map, and press the space bar. When I press the space bar, I am basically immobile. However, it should take a certain amount of seconds for me to retrieve the object. Now, I am wondering what the best way to do this be without changing the functionality. So, if I am on top of the object, I press space bar I am meant to ensure that the key remains pressed down for approximately 5 seconds. Which would mean I have to start the timer somewhere, but im still not sure how to approach this. Examples using function KeyPressed(), KeyIsDown(), KeyReleased() would be helpful. Thank you
Edit: So currently, I have been thinking of using a counter (not that effective at all but it is what it is), but then I am thinking instead of looking at having a global timer.
Example Code:
`
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
let PickUpRate = 0
push()
let x = 100
let y = 100
let size = 64
fill(100,63)
//base
rect(x-size/2, y-size/2-20,size,10);
//health
fill(0,220,0)
rect(x-size/2, y-size/2-20,size*abs(PickUpRate)/100,10);
pop()
}
function keyPressed(event){
console.log(event.timeStamp)
}
function keyReleased(event){
console.log(event.timeStamp)
}
`
This is what I have to work with so far, but I have to also increment my bar somehow using the timestamp? How should this be done?
You could use timestamps and/or application time to evaluate if a certain progress has been made.
I created a little snippet to demonstrate the thought on how to do it. This might not be the best solution but it should give you a hint in the right direction.
On KeyPressed -> Get Time.
While KeyIsDown -> Check whether the time holding the Button is equal to timeToPickUp, if not calculate progress as percent and update the progress bar.
As soon as the value reaches/exceeds 100, perform action and stop drawing the progress bar.
I never worked with p5js before, therefore the code is certainly not "production ready", but you get the idea.
let timeToPickUp = 5000; //ms of time to pick up
let startOfPickUp = 0; // var to save timeStamp to
let progress = 0; // var to save progress value
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
let PickUpRate = 0
push()
let x = 100
let y = 100
let size = 64
fill(100,63)
//base
rect(x-size/2, y-size/2-20,size,10);
//health
fill(0,220,0)
rect(x-size/2, y-size/2-20,size*abs(PickUpRate)/100,10);
pop()
if(keyIsDown(32)) { // Check if spacebar is pressed
if(startOfPickUp > 0 && progress < 100) { // Don't draw if invalid
progress = (millis() - startOfPickUp) / timeToPickUp * 100; //get progress
//draw progress
fill(255,0,0)
rect(10, 350, progress, 25)
if(progress >= 100) {
console.log('do whatever is supposed to happen automatically');
}
}
}
}
function keyPressed(event){
startOfPickUp = millis() // get start
}
function keyReleased(event){
startOfPickUp = 0; // remove values when released
progress = 0;
}
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.js"></script>
Here's a quick proof of concept implementation using setTimeout:
// class to encapsulate the progress tracking and meter updating
class Progress {
constructor(elem, duration = 2000, updateInterval = 50) {
// the meter DOM element
this.elem = elem;
// the currently active timeout id
this.timeoutId = null;
// when progress tracking started
this.startTime = null;
// how long it takes to complete
this.duration = duration;
// how frequently to update the meter
this.updateInterval = updateInterval;
}
start() {
if (this.startTime) {
// already running
return;
}
// track when it started
this.startTime = Date.now();
// start updating
this.timeoutId = setTimeout(() => this.update(), this.updateInterval);
}
stop() {
// cancel the timeout if it exists
clearTimeout(this.timeoutId);
// reset the meter css
this.elem.style.setProperty('--complete', '0%');
this.elem.classList.remove('complete');
// clear our internal variables
this.timeoutId = null;
this.startTime = null;
}
update() {
// compute the percentage complete based on start time and current time, and cap it at 100%
const percentComplete = Math.min((Date.now() - this.startTime ?? Date.now()) / this.duration, 1) * 100;
// set the css property used to do the fill
this.elem.style.setProperty('--complete', `${percentComplete}%`);
if (percentComplete >= 100) {
// if we're at 100%, add the 'complete' class to the meter
this.elem.classList.add('complete');
}
else {
// otherwise set up the next update
this.timeoutId = setTimeout(() => this.update(), this.updateInterval);
}
}
}
// create an instance of Progress for our meter element
const progress = new Progress(document.getElementById('meter'));
// start on keydown
document.body.addEventListener('keydown', () => {
progress.start();
})
// stop on keyup
document.body.addEventListener('keyup', () => {
progress.stop();
})
#meter {
height: 20px;
max-width: 200px;
margin: 2rem auto;
/* use a custom property 'complete' to fill the appropriate amount of the bar */
background: linear-gradient(90deg, var(--fillColor, limegreen) var(--complete, 0%), #eee var(--complete, 0%) 100%);
}
/* class and animation for flashing the box shadow upon completion */
.complete {
animation: .1s ready infinite alternate;
}
@keyframes ready {
from {
box-shadow: 0 0 2px 4px red;
}
to {
box-shadow: 0 0 0 0px red;
}
}
<div id="meter"></div>