how can i make all sprites move to different attraction points using p5.js /p5.play - p5.js

I am creating a game and have sprites falling from the top of the canvas and destroying towers at the bottom of the canvas. I am trying to use attractionPoint on all the different towers so the sprites are moving towards the towers. I have currently gotten one sprite to move to a tower using attactionPoint but the remaining sprites continue to move in a straight path. Is there a way I am able to set multiple attraction points so the sprites are moving toward all towers?
see code below:
function createAsteroids() {
// code to spawn asteroids at random locations
for (let i = 0; i < numAsteroids; i++) {
asteroid = createSprite(random(0, 1000), random(-50, -350), 40, 40);
asteroid.maxSpeed = random(1, 3);
rock.add(asteroid);
asteroidArray.push(asteroid);
}
}
function drawAsteroid() {
// draws asteroids moving down and checking collision
rock.overlap(turret, explode);
for (let i = 0; i < asteroidArray.length; i++) {
if (asteroidArray[i].position.y > height) {
asteroidArray[i].position.y = 0;
asteroidArray[i].position.x = random(0, 800);
}
asteroidArray[i].addSpeed(3, 90);
asteroid.attractionPoint(1, 100, 740);
asteroid.attractionPoint(1, 400, 740);
asteroid.attractionPoint(1, 700, 740);
}
}
function explode(sprite, obstical) {
//code for explosion and collision
sprite.remove();
obstical.remove();
}

You're very close but there's a couple things that aren't quite correct. In drawAsteroid you're setting the attractionPoint on only the lastly created asteroid, and doing it 3 times and calling it - i assume - in the draw method so it would get updated each frame. We only really want the drawAsteroid function for its respawning logic, so let's rename this method to updateAsteroid rather than drawAsteroid because we're going to call drawSprites(rock); in the draw method (rock is the group you've created for your asteroids).
When we set the attractionPoint we only want to do that once and that's when we create the asteroid:
function createAsteroids() {
// code to spawn asteroids at random locations
for (let i = 0; i < numAsteroids; i++) {
let asteroid = createSprite(random(0, width), random(-50, -350), 40, 40);
asteroid.maxSpeed = random(1, 3);
rock.add(asteroid);
let tower = floor(random(3)) // i know there's only 3 asteroids, you could do something better here
asteroid.attractionPoint(asteroid.maxSpeed, towers[tower].position.x, towers[tower].position.y);
}
}
So we're just randomly targeting a tower from the group.
I've set up a small example that should point you in the right direction.
// Find my blog at https://codeheir.com/
// I do a lot of p5.js stuff that might interest you!
let numAsteroids = 10;
let towers;
let rock;
function setup() {
createCanvas(400, 400);
rock = Group();
towers = Group();
createTowers();
createAsteroids();
}
function draw() {
background(220);
drawSprites(rock);
drawSprites(towers);
updateAsteroids();
}
function createAsteroids() {
// code to spawn asteroids at random locations
for (let i = 0; i < numAsteroids; i++) {
let asteroid = createSprite(random(0, width), random(-50, -350), 40, 40);
asteroid.maxSpeed = random(1, 3);
rock.add(asteroid);
let tower = floor(random(3))
asteroid.attractionPoint(asteroid.maxSpeed, towers[tower].position.x, towers[tower].position.y);
}
}
function updateAsteroids() {
// draws asteroids moving down and checking collision
//rock.overlap(turret, explode);
for (let i = 0; i < rock.length; i++) {
if (rock[i].position.y > height) {
rock[i].position.y = 0;
rock[i].position.x = random(0, width);
}
}
}
function createTowers() {
towers.push(createSprite(40, height - 30, 40, 90));
towers.push(createSprite(width/2, height - 30, 40, 90));
towers.push(createSprite(width-40, height - 30, 40, 90));
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.sound.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/molleindustria/p5.play/lib/p5.play.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
I've also created a p5.js sketch to point you in the right direction.

Related

Creating a mask layer in p5js

I would like to draw a pattern, and then only have that pattern ‘show through’ where it overlaps with a shape that I specify. Similar to how a mask layer works in Photoshop. Does anyone know how I can approach this?
I would use this 4 step process:
create your mask with beginShape()/endShape and a beginContour()/endContour() in the middle for the area to be shown. You do this on a buffer.
function setup() {
createCanvas(400, 400);
background(30)
fill(200,50,60)
msk = createGraphics(width,height)
pattern = createGraphics(width,height)
pixelDensity(1)
msk.beginShape();
// Exterior part of shape, clockwise winding
msk.vertex(0, 0);
msk.vertex(400, 0);
msk.vertex(400, 400);
msk.vertex(0, 400);
// Interior part of shape, counter-clockwise winding
msk.beginContour();
msk.vertex(20, 20);
msk.vertex(50, 220);
msk.vertex(120, 380);
msk.vertex(370, 320);
msk.vertex(240, 160);
msk.vertex(350, 40);
msk.endContour();
msk.endShape(CLOSE);
mPixs = msk.loadPixels()
}
Then create a different buffer for the pattern
for (let c=0; c<9; c++) {
for (let r=0; r<9; r++) {
pattern.circle(width/8*c,height/8*r,40)
}
}
Now load pixels from the mask and use the alpha value of each pixel on the alpha level of each corresponding pixel on the pattern.
pattern.loadPixels()
msk.loadPixels()
for (let i=0; i < pattern.pixels.length; i+=4){
pattern.pixels[i+3] = msk.pixels[i+3]
}
pattern.updatePixels()
Finally, just add the resulting buffer to your main canvas with image(pattern,0,0)
Take a look at this working example carefully coded just for you! :D
let msk, pattern, mPixs
function setup() {
createCanvas(400, 400);
background(30)
fill(200,50,60)
msk = createGraphics(width,height)
pattern = createGraphics(width,height)
pixelDensity(1)
msk.beginShape();
// Exterior part of shape, clockwise winding
msk.vertex(0, 0);
msk.vertex(400, 0);
msk.vertex(400, 400);
msk.vertex(0, 400);
// Interior part of shape, counter-clockwise winding
msk.beginContour();
msk.vertex(20, 20);
msk.vertex(50, 220);
msk.vertex(120, 380);
msk.vertex(370, 320);
msk.vertex(240, 160);
msk.vertex(350, 40);
msk.endContour();
msk.endShape(CLOSE);
mPixs = msk.loadPixels()
}
function draw() {
for (let c=0; c<9; c++) {
for (let r=0; r<9; r++) {
pattern.circle(width/8*c,height/8*r,40)
}
}
for (let c=0; c<9; c++) {
for (let r=0; r<9; r++) {
let xo=random(-5,5), yo=random(-5,5)
circle(width/8*c+xo,height/8*r+yo,50)
}
}
pattern.loadPixels()
msk.loadPixels()
for (let i=0; i < pattern.pixels.length; i+=4){
pattern.pixels[i+3] = msk.pixels[i+3]
}
pattern.updatePixels()
image(pattern,0,0)
}
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<main>
</main>
<script src="sketch.js"></script>
</body>
</html>

How to detect collisions between a moving point and the stroke of an arbitrary boundary shape?

I want to draw a circle(for example) and create a couple of points inside that circle. The points are moving randomly, but when they hit the circle's stroke, they should either stop or go inverse or react in some way (it's not that important). I know it would be easy to do with rect-like shapes, but I want to draw inside custom shapes like stars or flower.
To find out if point inside the circle or not you just need to calculate distance from center of circle to point itself. If that distance less then radius - point inside circle.
Fun example:
let c, r;
let points = [];
function setup()
{
createCanvas(200, 200);
r = 50;
c = createVector(100, 100);
let pos = createVector(95, 110);
let v = p5.Vector.random2D();
points.push({p: pos, v: v});
}
function draw()
{
background(0);
points.forEach(point => {
point.p.add(point.v);
if(point.p.dist(c) > r) {
let n = point.p.copy().sub(c).normalize();
let d_n = point.v.dot(n);
point.v = p5.Vector.sub(n.mult(2).mult(d_n), point.v).mult(-1);
//pv.mult(-1);
}
circle(point.p.x,point.p.y,5);
});
noFill();
stroke(255);
circle(c.x,c.y, r*2);
}
function mouseClicked() {
let p = createVector(mouseX, mouseY);
if (p.dist(c) < r) {
points.push({
p: p,
v: p5.Vector.random2D(),
});
}
// prevent default
return false;
}
<script src="https://github.com/processing/p5.js/releases/download/v1.4.0/p5.min.js"></script>
click inside circle
Boring example:
let c, radius;
function setup()
{
createCanvas(200, 200);
c = createVector(100, 100);
radius = 50;
}
function draw()
{
background(0);
let point = createVector(mouseX, mouseY);
let distance = c.dist(point);
if (distance > radius) {
fill("red");
} else {
fill("green");
};
circle(c.x, c.y, radius * 2);
// just rendering text :)
stroke(255);
line(point.x,point.y, c.x,c.y);
stroke(0);
fill(200)
push()
translate(p5.Vector.add(c, p5.Vector.sub(point, c).div(2)));
text(distance.toFixed(2),0,0)
pop()
text("Move your mouse",20,10);
}
<script src="https://github.com/processing/p5.js/releases/download/v1.4.0/p5.min.js"></script>

How do I make a object move towards the mouse in p5.js?

I'm making a zombie game in p5js, does anyone have any recommendations on to make a shape or object move towards the mouse(this will be used to make the gun)? and if anyone knows how to make more enemies spawn more often each round that would be nice to!:)
Sorry if the solution is super simple, I still kinda new!
code:
let dogmode;
let round;
let zombie, player;
let x, y;
let health, speed, damage, playerhealth;
function setup() {
dogmode=false;
createCanvas(400,400);
round = 1;
bullet ={
damage:20
};
//Player and zombie parameters
zombie = {
pos: createVector(500, 200),
//increase by 100 each round until round 9
health: 150,
speed: 1,
};
player = {
pos: createVector(200, 200),
//default
health: 100,
};
fill(0);
}
function draw() {
if( dogmode===true){
player.health=player.health+100;
}
background(220);
stroke(0);
line(player.pos.x,player.pos.y,mouseX,mouseY);
fill('gray')
ellipse(mouseX,mouseY,10,10);
push();
//player
fill("green");
ellipse(player.pos.x, player.pos.y, 20, 20);
//HUD or something
fill("black");
text("" + player.health, 10, 10);
//zombie(s)
fill("gray");
rect(zombie.pos.x, zombie.pos.y, 20, 20);
//Damage system
if (p5.Vector.sub(player.pos, zombie.pos).mag() <= 30) {
player.health = player.health - 1;
}
//Health detection
if (player.health <= 0) {
background(0);
textSize(20);
text("You died \n Round " + round, 165, 200);
}
if (keyIsDown(87)) {
player.pos.y -= 2;
}
if (keyIsDown(83)) {
player.pos.y += 2;
}
if (keyIsDown(65)) {
player.pos.x -= 2;
}
if (keyIsDown(68)) {
player.pos.x += 2;
}
zombie.pos.add(p5.Vector.sub(player.pos, zombie.pos).limit(zombie.speed))
pop();
//Create bullet
if(mouseIsPressed ){
fill('yellow')
ellipse(mouseX,mouseY,5,5);
//Shoots bullet
}
}
In order to fire a bullet you need to:
Determine the direction of motion at the time the bullet is fired.
Save that vector so that the direction remains constant for the life of the bullet.
Update the position of the bullet each frame after it is fired.
Determining the direction of motion is simple vector arithmetic if you have two vectors, A and B, and subtract A - B you will get a vector representing the offset from B to A (i.e. pointing in the direction of A from B):
It is important to save this direction vector, because as the player, mouse, and bullet move the result of this computation will continually change; and bullets don't usually change direction once fired.
const BULLET_SPEED = 5;
let player;
let bullet;
function setup() {
createCanvas(windowWidth, windowHeight);
bullet = {
damage: 20,
};
player = {
pos: createVector(width / 2, height / 2),
//default
health: 100,
};
}
function draw() {
background(220);
stroke(0);
// By taking the difference between the vector pointing to the mouse and the
// vector pointing to the player we get a vector from the player to the mouse.
let mouseDir = createVector(mouseX, mouseY).sub(player.pos);
// Limit the length to display an indicator of the bullet direction
mouseDir.setMag(30);
// Because we want to draw a line to the point mouseDir offset away from
// player, we'll need to add mouseDir and player pos. Do so using the static
// function so that we don't modify either one.
let dirOffset = p5.Vector.add(player.pos, mouseDir);
// direction indicator
line(player.pos.x, player.pos.y, dirOffset.x, dirOffset.y);
fill("gray");
ellipse(dirOffset.x, dirOffset.y, 10, 10);
//player
fill("green");
ellipse(player.pos.x, player.pos.y, 20, 20);
if (keyIsDown(87)) {
player.pos.y -= 2;
}
if (keyIsDown(83)) {
player.pos.y += 2;
}
if (keyIsDown(65)) {
player.pos.x -= 2;
}
if (keyIsDown(68)) {
player.pos.x += 2;
}
//Create bullet
if (mouseIsPressed) {
// Notice there can be only one bullet on the screen at a time, but there's
// no reason you couldn't create multiple bullets and add them to an array.
// However, if you did, you might want to create bullets in a mouseClicked()
// function instead of in draw() lets you create too many bullets at a time.
bullet.firing = true;
// Save the direction of the mouse;
bullet.dir = mouseDir;
// Adjust the bullet speed
bullet.dir.setMag(BULLET_SPEED);
// Position the bullet at/near the player
bullet.initialPos = dirOffset;
// Make a copy so that initialPos stays fixed when pos gets updated
bullet.pos = bullet.initialPos.copy();
//Shoots bullet
}
if (bullet.firing) {
fill('yellow');
ellipse(bullet.pos.x, bullet.pos.y, 5, 5);
// move the bullet
bullet.pos.add(bullet.dir);
if (bullet.pos.dist(bullet.initialPos) > 500) {
bullet.firing = false;
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

How to remove a 'bullet ' sprite after it has reached mouseX and mouseY? [P5.Play]

I'm making a game using P5.Play, where I have 3 obelisks; one on the left, one on the right and one in the middle. I have made it so if my mouse position is within a specific area of the canvas, the obelisk nearest will shoot towards my mouse position. However I am struggling to find a way to get the sprite to explode once it has reached the x and y point at which when I clicked the mouse. I won't post my full code because it's for an assignment but here is a snippet.
function mousePressed() {
if (mouseX < width / 3) {
bullet = createSprite(obelisks[0].position.x, obelisks[0].position.y - 60, 20, 20)
} else if (mouseX > width / 3 && mouseX < width - width / 3) {
bullet = createSprite(obelisks[1].position.x, obelisks[1].position.y - 60, 20, 20)
} else {
bullet = createSprite(obelisks[2].position.x, obelisks[2].position.y - 60, 20, 20)
}
// if bullet position is less than the distance between firing point and cursor position, then remove bullet??
bullet.addImage(bulletSprite);
bullet.attractionPoint(10, mouseX, mouseY);
bullet.rotateToDirection = true;
}
First of all, thank you for introducing me to p5.play!
There's a couple of things to think about here, but you're very close. From reading the documentation there's a function on the sprite object called overlapPoint(pointX, pointY) which:
Checks if the given point is inside the sprite's collider.
This returns a boolean. We can leverage this to determine if our bullet has reached its destination.
First of all, let's define the destinationX and destinationY properties on our object:
function mousePressed() {
...
bullet = createSprite(width/2, height, 10, 10);
let destinationX = mouseX;
let destinationY = mouseY;
bullet.attractionPoint(10, destinationX, destinationY);
bullet.destinationX = destinationX;
bullet.destinationY = destinationY;
}
Now, we can use these properties to determine if we've hit the overlap point:
function draw() {
background(220);
drawSprite(obelisk);
if (bullet) {
drawSprite(bullet);
if (bullet.overlapPoint(bullet.destinationX, bullet.destinationY)) {
bullet.remove();
}
}
}
Here's a working, simplified example:
let obelisk;
let bullet;
function setup() {
createCanvas(400, 400);
obelisk = createSprite(width/2, height, 50, 200);
}
function draw() {
background(220);
drawSprite(obelisk);
if (bullet) {
drawSprite(bullet);
if (bullet.overlapPoint(bullet.destinationX, bullet.destinationY)) {
bullet.remove();
}
}
}
function mousePressed() {
bullet = createSprite(width/2, height, 10, 10);
let destinationX = mouseX;
let destinationY = mouseY;
bullet.attractionPoint(10, destinationX, destinationY);
bullet.destinationX = destinationX;
bullet.destinationY = destinationY;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.sound.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/molleindustria/p5.play/lib/p5.play.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
And here's a link to a p5.js sketch I created, to help you further.
Hopefully, this points you in the right direction. I might also recommend that you create an array of bullets, such: let bullets = [] and add to this array when you shoot, this would prevent the deletion of a bullet when shooting in rapid succession. Or you could maybe even look into p5.play's grouping object.

how can I use parcel.js to run p5.js code?

I've lately been using parcel.js with react apps and it's been very user friendly.
I'm following along to a Coding Train tutorial and parcel for whatever reason is not running the code.
https://github.com/CodingTrain/website/tree/master/CodingChallenges/CC_001_StarField/P5
When I run this with live server, no errors and everything runs correctly.
When I attempt to run it with parcel.js, there are no errors, it just doesn't run, nothing renders.
Any idea why this might be happening?
Thank you
I think the issue here is that Parcel.js doesn't put variables defined in src'd scripts into the global scope by default, and p5.js depends on these globals by default (setup and draw in particular). You could solve the problem by making speed, setup and draw in sketch.js, and Star in Star.js, properties of window (or, equivalently, global). See the example below, which works when built with parcel index.html.
(This method has the benefit of preserving access to the familiar (global) p5.js commands without the need for a prefix, but might give complications with globals being overwritten if you're using other libraries.)
//sketch.js
let stars = [];
window.speed = undefined;
window.setup = function setup() {
createCanvas(600, 600);
for (let i = 0; i < 800; i++) {
stars[i] = new Star();
}
}
window.draw = function draw() {
speed = map(mouseX, 0, width, 0, 50);
background(0);
translate(width / 2, height / 2);
for (let i = 0; i < stars.length; i++) {
stars[i].update();
stars[i].show();
}
}
//Star.js
window.Star = function Star() {
this.x = random(-width, width);
this.y = random(-height, height);
this.z = random(width);
this.pz = this.z;
this.update = function() {
this.z = this.z - speed;
if (this.z < 1) {
this.z = width;
this.x = random(-width, width);
this.y = random(-height, height);
this.pz = this.z;
}
};
this.show = function() {
fill(255);
noStroke();
var sx = map(this.x / this.z, 0, 1, 0, width);
var sy = map(this.y / this.z, 0, 1, 0, height);
var r = map(this.z, 0, width, 16, 0);
ellipse(sx, sy, r, r);
var px = map(this.x / this.pz, 0, 1, 0, width);
var py = map(this.y / this.pz, 0, 1, 0, height);
this.pz = this.z;
stroke(255);
line(px, py, sx, sy);
};
}
<html>
<head>
<meta charset="UTF-8" />
<title>StarField_p5.js</title>
<style>
body {
padding: 0;
margin: 0;
}
canvas {
vertical-align: top;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/p5#1.0.0/lib/p5.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/p5#1.0.0/lib/addons/p5.sound.min.js"></script>
<script src="./Star.js"></script>
<script src="./sketch.js"></script>
</head>
<body>
<main></main>
</body>
</html>
Alternatively you could use instance mode of P5.js to set things up without globals (See also thread here - the code sample of which has now had its P5.js dependency removed, but you can look at the commit history). This has the downside that the familiar P5.js / processing functions have to be prefixed with an object reference, minimally something like s.createCanvas (the methods often seem to depend on being bound properly in object orientated style). It is likely the safer approach if other libraries are involved though, especially as p5.js defines lots of globals with common names like random, map and height if it isn't used in instance mode.
Something like this:
// index.js
// I've combined sketch.js and Star.js here to make
// it easier to share variable speed
const myp5 = new p5((s) => {
const stars = [];
let speed =1;
s.setup = function setup() {
s.createCanvas(600, 600);
for (let i = 0; i < 800; i++) {
stars[i] = new Star();
}
};
s.draw = function draw() {
speed = s.map(s.mouseX, 0, s.width, 0, 50);
s.background(0);
s.translate(s.width / 2, s.height / 2);
for (let i = 0; i < stars.length; i++) {
stars[i].update();
stars[i].show();
}
};
function Star() {
this.x = s.random(-s.width, s.width);
this.y = s.random(-s.height, s.height);
this.z = s.random(s.width);
this.pz = this.z;
this.update = function () {
this.z = this.z - speed;
if (this.z < 1) {
this.z = s.width;
this.x = s.random(-s.width, s.width);
this.y = s.random(-s.height, s.height);
this.pz = this.z;
}
};
this.show = function () {
s.fill(255);
s.noStroke();
var sx = s.map(this.x / this.z, 0, 1, 0, s.width);
var sy = s.map(this.y / this.z, 0, 1, 0, s.height);
var r = s.map(this.z, 0, s.width, 16, 0);
s.ellipse(sx, sy, r, r);
var px = s.map(this.x / this.pz, 0, 1, 0, s.width);
var py = s.map(this.y / this.pz, 0, 1, 0, s.height);
this.pz = this.z;
s.stroke(255);
s.line(px, py, sx, sy);
};
}
},'sketch1');
<html>
<head>
<meta charset="UTF-8" />
<title>StarField_p5.js</title>
<style>
body {
padding: 0;
margin: 0;
}
canvas {
vertical-align: top;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/p5#1.0.0/lib/p5.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/p5#1.0.0/lib/addons/p5.sound.min.js"></script>
<script src="./index.js"></script>
</head>
<body>
<div id="sketch1"></div>
</body>
</html>

Resources