I'm new to JavaScript and wanted to code a game I had previously coded in Java. I was coding with the p5.js library, and using the Atom text editor. The game I was making was Asteroids and it was working fine. I had figured out how to add the ship and the lasers. Then I added the code for the actual asteroids. (I'm not sure if this is relevant or not, but as I said before, I was copying the code from a Java project and when I went to add the asteroids I basically copied the whole thing over, without saving it until I was done.) After I added them, I tried to run it, and I said "asteroid is not defined", because I forgot to add a reference to it in the HTML. However, after I ran it again, the page stopped loading and eventually crashed (I got the "Aw, Snap! Something went wrong when displaying this webpage" error). I thought it was the HTML at first, but when I added the class to the main script, it still crashed. After an hour, I realized that if I added parenthesis to the class name (class ship(){}) then the page would load. However, I would get a syntax error as expected. The same thing would happen if I declared the object as the class like you would do in Java (Ship ship;), it would run but it would say "Uncaught SyntaxError: Unexpected identifier". I'm not sure how to get around this, or why not adding parenthesis to a class name would cause the program not to run.
Attached are the first part of my main script, the constructor of my ship class, and my asteroid class because the problems only started after adding it.
Any help or solutions to this problem would be greatly appreciated.
Main Script:
let ship;
let bullets = [];
let asteroids = [];
// Left Right Boost Slow Shoot
let keyDown = [false, false, false, false, false];
function setup(){
window.canvas = createCanvas(800, 600);
ship = new Ship(width/2, height/2);
for(let i = 0; i = 4; i++){
asteroids.push(new asteroid(random(width), random(height), 100));
}
frameRate(60);
}
function draw(){
background(0);
checkKeys();
ship.update();
ship.show();
for(let i = bullets.length-1; i >= 0; i--){
bullets[i].update();
bullets[i].show();
if(!bullets[i].alive){
bullets.splice(i, 1);
}
}
for(let i = asteroids.length-1; i >= 0; i--){
asteroids[i].update();
asteroids[i].show();
}
}
Ship Class:
class Ship{
constructor(x, y){
this.x = x;
this.y = y;
this.velX = 0;
this.velY = 0;
this.midX = this.x + 15;
this.midY = this.y + 20;
this.heading = 0;
this.rotation = 0;
this.boosting = false;
}
Asteroid Class:
class asteroid{
constructor(x, y, size){
this.x = x;
this.y = y;
this.size = size;
this.velX = random(-2, 3);
this.velY = random(-2, 3);
if(this.velX == 0){
this.velX++;
}
if(this.velY == 0){
this.velY++;
}
this.points = random(4, 12);
this.xPoints = [];
this.yPoints = [];
this.offsets = [];
for(let i = 0; i < this.points; i++){
this.offsets[i] = random(-size/5, (size/5)+1);
}
}
update(){
this.x += this.velX;
this.y += this.velY;
}
show(){
stroke(255);
beginShape();
for(let i; i < this.points; i++){
let angle = i*(360/this.points);
let px = (this.size/2 + this.offsets[i]) * cos(angle);
let py = (this.size/2 + this.offsets[i]) * sin(angle);
this.xPoints[i] = px + this.x;
this.yPoints[i] = py + this.y;
vertex(px, py);
}
endShape(CLOSE);
}
}
Running the code, I got the same error. Turns out your ship class has no closing bracket } for the class, only for the constructor. Adding that and now I get no errors
let ship;
let bullets = [];
let asteroids = [];
// Left Right Boost Slow Shoot
let keyDown = [false, false, false, false, false];
function setup(){
window.canvas = createCanvas(800, 600);
ship = new Ship(width/2, height/2);
for(let i = 0; i = 4; i++){
asteroids.push(new asteroid(random(width), random(height), 100));
}
frameRate(60);
}
function draw(){
background(0);
checkKeys();
ship.update();
ship.show();
for(let i = bullets.length-1; i >= 0; i--){
bullets[i].update();
bullets[i].show();
if(!bullets[i].alive){
bullets.splice(i, 1);
}
}
for(let i = asteroids.length-1; i >= 0; i--){
asteroids[i].update();
asteroids[i].show();
}
}
class Ship{
constructor(x, y){
this.x = x;
this.y = y;
this.velX = 0;
this.velY = 0;
this.midX = this.x + 15;
this.midY = this.y + 20;
this.heading = 0;
this.rotation = 0;
this.boosting = false;
}
} //<--- I added this bracket
class asteroid{
constructor(x, y, size){
this.x = x;
this.y = y;
this.size = size;
this.velX = random(-2, 3);
this.velY = random(-2, 3);
if(this.velX == 0){
this.velX++;
}
if(this.velY == 0){
this.velY++;
}
this.points = random(4, 12);
this.xPoints = [];
this.yPoints = [];
this.offsets = [];
for(let i = 0; i < this.points; i++){
this.offsets[i] = random(-size/5, (size/5)+1);
}
}
update(){
this.x += this.velX;
this.y += this.velY;
}
show(){
stroke(255);
beginShape();
for(let i; i < this.points; i++){
let angle = i*(360/this.points);
let px = (this.size/2 + this.offsets[i]) * cos(angle);
let py = (this.size/2 + this.offsets[i]) * sin(angle);
this.xPoints[i] = px + this.x;
this.yPoints[i] = py + this.y;
vertex(px, py);
}
endShape(CLOSE);
}
}
Related
I am creating an endless racing game with p5.js and I am currently facing the biggest problem in its development. I need the other cars/obstacles to spawn randomly but in an ordered fashion, each one in its lane and leaving enough space for the player's car to drive through. Do you have any suggestion how can I achieve this? Thanks in advance.
What I managed to do so far is to create classes of obstacles, set their position and give them different speeds. But this doesn't create randomness of course.
class Obstacle1 {
constructor() {
this.x = 120
this.y = 0;
this.speed = 2
}
draw() {
image(this.imgObst1, this.x, this.y, 60, 120)
this.y += this.speed
if (this.y >= height){
this.y = 0
}
}
preload() {
this.imgObst1 = loadImage('/resources/player/car.png')
}
}
Try that:
let ob = [];
function setup() {
createCanvas(400, 400);
for(let i = 0; i < 4; i ++){
coords[i] = i*120;
}
for(let i = 0; i < 3; i ++){
ob[i] = new Obstacle1();
}
}
function draw() {
background(0);
for(let i = 0; i < 3; i ++){
ob[i].draw();
}
}
class Obstacle1 {
constructor() {
this.x = random(coords);
this.y = 0;
this.speed = 2
}
draw() {
rect(this.x, this.y, 60, 120)
this.y += this.speed
if (this.y >= height){
this.y = 0
}
}
}
if I understand correctly this should work.
I recommend you create a pickRandom() function
Ex-
function pickRandom(){
x= random(20,width-20)
}
Although you will need to adjust the code for this particular instance
I would also recommend you add a if statement with pickRandom() function in it.
I'm trying to achieve that, everytime you type a different letter key, the lines of the letters 'merge' into eachother instead of just 'jumping' to the next letter like it's doing now. I'm looking into the lerp() function but i'm not sure how to apply this to my code. Can someone help me into the right direction? This is what i have untill now:
var redtown;
var fontSize = 500;
var myArray;
var r = 3;
function preload(){
redtown = loadFont('redtown.otf');
}
function setup(){
createCanvas(windowWidth,windowHeight);
textFont(redtown);
textSize(fontSize);
}
function draw(){
background(0);
myArray = redtown.textToPoints(key, width/2, 500, fontSize, {
sampleFactor:0.5
});
// text(key, width/2, height/2 );
for (var i = 0; i < myArray.length; i++) {
// ellipse(myArray[i].x, myArray[i].y, 10, 10)
push();
translate(myArray[i].x, myArray[i].y);
rotate(r);
r++;
stroke(255);
strokeWeight(1);
line(-10,-10,10,10,10);
frameRate(17);
pop();
}
}
Here is a snippet that transitions from one character to another by using textToPoints to get the points from the last two keys that have been pressed and then slides each point in the old character to its position in the new character.
It uses this formula to get the x and y positions of points along a line from the point in the old character to the point in the new character.
x = (1-t)*x+t*nextX;
y = (1-t)*y+t*nextY;
It also uses the spinning lines idea from the question to give the points some motion although it pins the line size to a constant.
rotate(r+=0.1);
line(-1,-1,1,1);
You can see it in action here Fonts Transition
var myFont;
var fontSize = 160;
var fontPoints =[];
var previousFontPoints = [];
var r = 0;
var oldKey = ' ';
function preload(){
myFont = loadFont('inconsolata.otf');
}
function setup(){
createCanvas(500, 500);
textFont(myFont);
textSize(fontSize);
frameRate(30);
stroke(255);
strokeWeight(1);
background(0);
}
function draw(){
if (oldKey != key){
previousFontPoints =
myFont.textToPoints(oldKey, width/10, height/2, fontSize, {
sampleFactor:1
});
oldKey = key;
fontPoints = myFont.textToPoints(key, width/10, height/2, fontSize, {
sampleFactor:1
});
t = 0.025;
}
t += .01;
if (fontPoints.length > 0 && t< 1.0){
background(0);
for (i = 0; i < fontPoints.length; i++){
let x = 0;
let y = 0;
// if we don't have enought points we will just float in from 0,0
let nextX = 0;
let nextY = 0;
push();
if (previousFontPoints.length > i){
x = previousFontPoints[i].x;
y = previousFontPoints[i].y;
// in case the new array does not have enough points
nextX = x;
nextY = y;
}
if (fontPoints.length > i){
nextX = fontPoints[i].x;
nextY = fontPoints[i].y;
}
x = (1-t)*x+t*nextX;
y = (1-t)*y+t*nextY;
translate(x, y);
rotate(r+=0.1);
line(-1,-1,1,1);
pop();
}
}
}
I saw many times really cool examples of kinetic typography. In these examples every letter is a particle. The text is a particle system and it may be subject to various forces such gravity or even centrifugal force. These systems are made in Processing and in p5.js.
I am building an interactive screen for the web filled with text using p5.js, inspired by these example of kinetic typography.
When the user moves the cursor on the text this start bounce all around the screen.
I translated the sketch from Processing to p5.js and I have noticed this problem related to the spacing of the text in the setup() function.
In Processing the code looks like this and it function correctly.
I want to focus on this section of the Processing code:
void setup() {
size(640, 360);
//load the font
f = createFont("Arial", fontS, true);
textFont(f);
// Create the array the same size as the String
springs = new Spring[message.length()];
// Initialize Letters (Springs) at the correct x location
int locx = 40;
//initialize Letters (Springs) at the correct y location
int locy = 100;
for (int i = 0; i < message.length(); i++) {
springs[i] = new Spring(locx, locy, 40, springs, i, message.charAt(i));
locx += textWidth(message.charAt(i));
//boudaries of text just to make it a nice "go to head"
if (locx >= 360) {
locy+=60;
locx = 40;
}
}
}
You can see the result
As you can see the parameter
springs[i] = new Spring(locx, locy, 40, springs, i, message.charAt(i));
locx += textWidth(message.charAt(i));
does its job, spacing the letters.
However when I translate this sketch in P5.js, I don't get the same nice spacing.
This is the same section but is the p5.js code:
function setup() {
createCanvas(640, 360);
noStroke();
textAlign(LEFT);
// Create the array the same size as the String
springs = new Array(message.length);
// Initialize Letters (Springs) at the correct x location
var locx = 10;
//initialize Letters (Springs) at the correct y location
var locy = 120;
for (var i = 0; i < message.length; i++) {
springs[i] = new Spring(locx, locy, 40, springs, i, message.charAt(i));
locx += textWidth(message.charAt(i));
//boudaries of text just to make it a nice "go to head"
if(locx>= 390){
locy+= 60;
locx= 40;
}
}
}
The result is show
I am sure, in the p5js code, that there is a problem regarding this part:
springs[i] = new Spring(locx, locy, 40, springs, i, message.charAt(i));
locx += textWidth(message.charAt(i));
Because I tried to fix it multiplying the value of the locx as shown here:
springs[i] = new Spring(locx*5, locy, 40, springs, i, message.charAt(i));
I then got
which can seems correct, but I'm sure it is not.
At this point I have no idea how to fix it, it must be something of p5.js I'm unaware of.
Any help is greatly appreciate.
//Edit
As suggested in the comment here you can find the Spring class written in p5.js:
// Spring class
class Spring {
constructor (_x, _y, _s, _others, _id, letter_) {
// Screen values
this.x_pos = this.tempxpos = _x;
this.y_pos = this.tempypos = _y;
this.size = _s;
this.over = false;
this.move = false;
// Spring simulation constants
this.mass = 8.0; // Mass
this.k = 0.2; // Spring constant
this.damp =0.98; // Damping
this.rest_posx = _x; // Rest position X
this.rest_posy = _y; // Rest position Y
// Spring simulation variables
//float pos = 20.0; // Position
this.velx = 0.0; // X Velocity
this.vely = 0.0; // Y Velocity
this.accel = 0; // Acceleration
this.force = 0; // Force
this.friends = _others;
this.id = _id;
this.letter = letter_;
}
update() {
if (this.move) {
this.rest_posy = mouseY;
this.rest_posx = mouseX;
}
this.force = -this.k * (this.tempypos - this.rest_posy); // f=-ky
this.accel = this.force / this.mass; // Set the acceleration, f=ma == a=f/m
this.vely = this.damp * (this.vely + this.accel); // Set the velocity
this.tempypos = this.tempypos + this.vely; // Updated position
this.force = -this.k * (this.tempxpos - this.rest_posx); // f=-ky
this.accel = this.force / this.mass; // Set the acceleration, f=ma == a=f/m
this.velx = this.damp * (this.velx + this.accel); // Set the velocity
this.tempxpos = this.tempxpos + this.velx; // Updated position
if ((this.overEvent() || this.move) && !(this.otherOver()) ) {
this.over = true;
} else {
this.over = false;
}
}
// Test to see if mouse is over this spring
overEvent() {
let disX = this.x_pos - mouseX;
let disY = this.y_pos - mouseY;
let dis = createVector(disX, disY);
if (dis.mag() < this.size / 2 ) {
return true;
} else {
return false;
}
}
// Make sure no other springs are active
otherOver() {
for (let i = 0; i < message.length; i++) {
if (i != this.id) {
if (this.friends[i].over == true) {
this.velx = -this.velx;
return true;
}
}
}
return false;
}
//the springs collides with the edges of the screen
box_collision() {
if(this.tempxpos+this.size/2>width){
this.tempxpos = width-this.size/2;
this.velx = -this.velx;
} else if (this.tempxpos - this.size/2 < 0){
this.tempxpos = this.size/2;
this.velx = -this.velx;
}
if (this.tempypos+this.size/2>height) {
this.tempypos = height-this.size/2;
this.vely = -this.vely;
} else if (this.tempypos- this.size/2 < 0) {
this.tempypos = this.size/2;
this.vely = -this.vely;
}
}
//the springs collides with each other
collide() {
for (var i = this.id + 1; i < message.length; i++) {
var dx = this.friends[i].tempxpos - this.tempxpos;
var dy = this.friends[i].tempypos - this.tempypos;
var distance = sqrt(dx*dx + dy*dy);
var minDist = this.friends[i].size/2 + this.size/2;
if (distance < minDist) {
var angle = atan2(dy, dx);
var targetX = this.tempxpos + cos(angle) * minDist;
var targetY = this.tempypos + sin(angle) * minDist;
var ax = (targetX - this.friends[i].tempxpos) * 0.01;
var ay = (targetY - this.friends[i].tempypos) * 0.01;
this.velx -= ax;
this.vely -= ay;
this.friends[i].velx += ax;
this.friends[i].vely += ay;
}
}
}
//display the letter Particle
display() {
if (this.over) {
fill(255, 0, 0);
} else {
fill(255);
}
noStroke();
textSize(fontS);
//for debugging
// ellipse(this.tempxpos, this.tempypos, this.size, this.size);
text(this.letter, this.tempxpos, this.tempypos);
}
pressed() {
if (this.over) {
this.move = true;
} else {
this.move = false;
}
}
released() {
this.move = false;
this.rest_posx = this.x_pos;
this.rest_posy = this.y_pos;
}
}
And here you can find the link to the P5.js editor with the code:
Spring text p5js code
note: I had to fix the Spring class because I didn't realize that all of my functions where initialized in the constructor. Now the functions that compose the Class are outside the constructor. I still haven't figured out how to fix the spacing problem.
I managed to resolve the issue.
As far as I understood the code was correct from the beginning.
What I missed through the journey was that I have to set the font size in the function setup() if I want to display the text on the screen correctly.
You can still see the result by checking the link to the p5.js editor I posted previously.
In fact, I'm making a background which has to kinda illustrate "influence".
I tried to make this with particles, generated from a given point on the screen, which are moving toward a random direction, and which blast after some lifetime they have. So the problem is, I succeeded some way to do it, but it's really slow. about 400 generators placed, and the browser starts to lag, and the thing is i need at least 400 of these. So is there anyway to optimise what I did?
Link on this pen.
my particle:
class Particle {
constructor(radius,speed,lifetime,aoe) {
this.speed = speed;
this.life = lifetime;
this.aoe = aoe;
}
throw() {
var r = random(TWO_PI);
var dx = cos(r);
var dy = sin(r);
var speedX = this.speed*dx;
var speedY = this.speed*dy;
return [speedX,speedY];
}
display(rootX,rootY,x,y) {
line(rootX,rootY,x,y);
}
blast(rootX,rootY,x,y) {
line(rootX,rootY,x,y);
ellipse(x,y,this.aoe,this.aoe);
}
}
and here's the generator:
class ParticleGenerator {
constructor(x,y,frequency, particle) {
this.x = x;
this.y = y;
this.f = frequency;
this.p = particle;
this.pX = this.x;
this.pY = this.y;
this.state = 0;
this.wait = 0;
this.dir = this.p.throw();
}
travel(sX,sY) {
this.pX += sX;
this.pY += sY;
}
activate() {
var d = (dist(this.x,this.y,this.pX,this.pY)/this.p.speed)/this.p.life;
if(this.state == 0)
this.dir = this.p.throw();
if (this.state < this.p.life) {
stroke(255,0,0);
fill(11)
this.travel(this.dir[0],this.dir[1]);
this.p.display(this.x,this.y,this.pX,this.pY);
this.state++;
}
if (this.state == this.p.life && this.wait < this.f) {
stroke(255,0,0,255-(this.wait*255)/this.f)
fill(255,0,0,255-(this.wait*255)/this.f);
this.p.blast(this.x,this.y,this.pX,this.pY);
this.wait++;
}
if (this.wait == this.f) {
this.state = 0;
this.wait = 0;
this.pX = this.x;
this.pY = this.y;
}
}
}
What I am trying to do in this code is to take one dead particle, and make live ones cling to it and become dead in the process. At the end I would wish to have something that looks nice and is just a pleasurable program to watch.
But I have a problem...
My code will freeze at seemingly random points while running it and say "can't read property 'show()' of undefined."
The error is on line 18 when it tries to run the "live[i].show();"
sometimes it happens right away and sometimes it takes awhile but it always happens. Any help is appreciated.
Thank you in advance.
var live = [];
var dead = [];
function setup() {
createCanvas(windowWidth, windowHeight);
background(255);
for (var i = 0; i < 100; i++) {
live.push(new particle(random(width), random(height), 1));
}
dead.push(new particle(width / 2, height / 2, 0))
}
function draw() {
background(255);
if (live.length > 0) {
for (var i = 0; i < live.length; i++) {
live[i].update(i);
live[i].show();
}
}
for (var i = 0; i < dead.length; i++) {
dead[i].show();
}
}
function particle(x, y, l) {
this.x = x;
this.y = y;
this.l = l;
this.speed = 5;
this.c = 200;
this.s = 50;
}
particle.prototype.update = function(dex) {
this.speed *= this.l;
this.x += random(-this.speed, this.speed)
this.y += random(-this.speed, this.speed)
if (this.x < 0) {
this.x = width;
} else if (this.x > width) {
this.x = 0;
}
if (this.y < 0) {
this.y = height;
} else if (this.y > height) {
this.y = 0;
}
for (var i = 0; i < dead.length; i++) {
if (dist(dead[i].x, dead[i].y, this.x, this.y) < this.s && dist(dead[i].x, dead[i].y, this.x, this.y) > 0) {
dead.push(new particle(this.x, this.y, 0));
live.splice(dex, 1);
}
}
}
particle.prototype.show = function() {
this.c *= this.l;
strokeWeight(this.s);
stroke(this.c);
point(this.x, this.y);
}
If you replace loop in the draw method with map it will solve your problem.
function draw() {
background(255);
live.map(function(curr,i){
curr.update(i);
curr.show();
})
dead.map(function(curr){
curr.show();
})
}
here is the plunkr of the updated code https://plnkr.co/edit/j5ueccmK4o7kbNKfeYQJ The error was caused because it was trying to access array larger than the maximum index of the array.
This is caused because you are mutating the array using splice in update method and it reduces its length while the for loop with previous length tries to loop the array beyond its length causing undefined.
Edit:
It is better to reduce the mutation in the code to avoid these errors.