I'm learning to use Processing.JS have have a very basic idea on what I'm doing. I'm learning to create objects using cases. The aim of this code is to create random objects (balls) that bounce around the screen and when the mouse is clicked a new ball is created, leaving the original and the new created. I want to be able to do this multiple times, with all of the balls randomly bouncing around. I have the code working for one ball and have the code to a point where I'm creating new objects and they are being added to an array, however every time I click the single ball just gets reset to the middle of the screen. This is the code:
//random ball maker
Ball[] newBall = new Ball[1];
void setup(){
size(500,500);
newBall[0] = new Ball();
}
void draw(){
//newBall.display();
// newBall.movement();
for (int i = 0; i < newBall.length; i++) { //Loops through all mrect objects
newBall[i].display();
}
for (int i = 0; i < newBall.length; i++) { //Loops through all mrect objects
newBall[i].movement();
}
}
void mousePressed(){
Ball ballInstance = new Ball();
newBall = (Ball[]) append(newBall, ballInstance);
}
class Ball{
float xpos, ypos, xspeed, yspeed;
Ball(){
xpos = width/2;
ypos = height/2;
xspeed = 2;
yspeed = 2.5;
println("created new ball");
}
void display(){
background(100,100,100);
fill(143,154,189);
ellipseMode(CENTER);
ellipse(xpos, ypos, 50,50);
}
void movement(){
xpos = xpos + xspeed;
ypos = ypos + yspeed;
if (xpos > width - 25 || xpos < 25){
xspeed *= -1; }
if (ypos > height - 25 || ypos < 25){
yspeed *= -1; }
}
}
I feel my issue is with the initiation of the object or with the "void draw" function . What am I doing wrong??
Calling the background() function clears everything from the screen.
You call background() from inside the display() function in the Ball class. That means you draw each ball, but the last ball clears out all of the previous balls.
Move that line to inside the main draw() function.
Related
So lately I've been trying to make a 2D Zelda-like game. I want to make a camera to follow the player.
So I looked at https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/translate, https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Transformations, and some others in my search (MDN has an article on it but I couldn't follow although it didn't look like what I was looking for).
I also didn't want to just center the player, I want to have a camera which has a limit, so you have to go a certain amount outside of the camera for the map to start scrolling.
function camera(data) {
var x, y;
if(I.x <= 2 && I.x >= -2 && I.y <= 2 && I.y >= -2) { x = 0; y = 0;}
if(I.x > 2) { x = -I.size; y = 0; }
if(I.x < -2) { x = I.size; y = 0; }
if(I.y > 2) { x = 0; y = -I.size; }
if(I.y < -2) { x = 0; y = I.size; }
ctx.translate(x, y);
draw.map();
draw.camera();
draw.players(data);
ctx.resetTransform();
}
draw.map() draws the tiles.
draw.camera() draws a little dotted box so I know the boundary of the camera.
draw.players(data) draws every player.
I.size refers to the size of each tile(16 in this case).
I.x & I.y are self explanatory.
I do have a working version(uses node and socket.io):
http://dais-jaackotorus.codeanyapp.com:8080/
EDIT:
Almost forgot! The problem with this code is that it follows the player for only one tile and then it doesn't any longer, and it goes outside of the camera range instead of staying inside and I dont understand why.
Here's a simplified example:
https://jsfiddle.net/2xbo0kas/
The trick is to start drawing the world around the player. So, in the jsfiddle, you can see the player is stationary but the map moves, so that the player is always centered into the viewport.
What the fiddle does not show is the final position of the player once you reach the edge of the map (where you'd draw a stationary map but update the player rectangle).
function draw() {
var startx = Math.max([player.x - size.width], 0);
var endx = Math.min(startx + size.width, map.length);
var starty = Math.max([player.y - size.height], 0);
var endy = Math.min(starty + size.height, map[0].length);
for (var x = startx; x < endx; x++) {
for (var y = starty; y < endy; y++) {
var drawx = x - startx;
var drawy = y - starty;
//draw tile
}
}
//draw player
}
So I am rendering a Polyline with the Y-Values of a sin wave with the code below
var amplitude = 50;
var dx = (TWO_PI / period) * 10
var yValues = new Array(floor(widthOfWave / xSpacing));
var poly = [];
this.calculate = () => {
//Increment theta
theta += 0.02;
//For every x value, calculate the y value with SIN function
var x = theta;
for(var i = 0; i < yValues.length; i++) {
yValues[i] = sin(x) * amplitude;
x += dx;
}
this.render = () => {
this.calculate();
ellipseMode(CENTER);
beginShape();
for(var i = 0; i < yValues.length; i++) {
var temp = createVector((i * spacing), windowWidth + yValues[i]);
curveVertex(temp.x, temp.y);
poly.push(temp);
}
endShape();
}
Which renders the wave
This is exactly what I want, but the problem I am having is when I try to incorporate p5.collide2d (Github Link Here). I want to have an ellipse, the 'Player' in this case, be able to ride the wave by holding left and right on the keyboard arrows. I haven't gotten to the keyboard interaction, because I am currently stuck on having the Ellipse (a perfect circle) not just falling through the curve at sometimes.
Here is my code for the current collision I am testing with.
this.checkCollision = (objX, objY, objSize) => {
var hit = false;
var hit = collideCirclePoly(objX, objY, objSize, poly);
return hit;
}
//Check for the collision
var hit = hill.checkCollision(player1.x, player1.y, player1.size);
if(hit) player1.didCollide();
//Player's didCollide function
this.didCollide = () => {
newSpeed = this.ySpeed * -0.8;
this.ySpeed = newSpeed;
}
This is how the circle (the "Player") and the wave intereact whenever I try to run it though.
I can't seem to figure out why the interaction is happening this way. I have tried extending the bounds of the collision, but it just makes it appear very glitchy and it still sometimes just passes through the wave with what appears to be no collision.
I am fairly new to p5.js and processing, so I am most likely missing something very simple. Thanks for your help ahead of time!
I'm working on a fish sprite animation. Currently when I add a piece of food then the sprite animation will move forward to eat it. But I am not able to make it swim smoothly toward the food. Sometimes the sprite animation will move up and down till it reach the food.
Here is how the sprite animation is moving towards the food:
Fish.prototype.chaseFood = function(index) {
if (this.xPos > foodArray[index].x + foodWidth) {
this.speedX = -1 * Math.abs(this.speedX);
} else if (this.xPos < foodArray[index].x) {
this.speedX = Math.abs(this.speedX);
}
if (this.yPos > foodArray[index].y + foodHeight) {
this.speedY = -1 * Math.abs(this.speedY);
} else if (this.yPos < foodArray[index].y) {
this.speedY = Math.abs(this.speedY);
}
};
Is there anyway to make it swim more smoothly towards the food and not moving up and down towards it.
I'd calculate angle between the fish and the food and make the fish move towards that angle.
Here are some helper functions to get you going:
function distanceBetweenPoints(a, b)
{
return Math.sqrt(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2));
}
function angleBetweenPoints(a, b)
{
return Math.atan2(b.y-a.y,b.x-a.x)*180/Math.PI;
}
Usage:
var angle = angleBetweenPoints({ x: fish.x, y: fish.y }, { x: food.x, y: food.y });
Then you can do something like:
fish.x += Math.sin(angle * Math.PI / 180) * 10;
fish.y += Math.cos(angle * Math.PI / 180) * 10;
I think you want your sprite to move in a direct line from one set of coordinates (it's location) to another set of coordinates (the food's location).
So if your if your x coordinates are a difference of 6 pixels and your y coordinates are a difference of 4, we want to keep the ratio of 6 to 4 when we increase our x and y offset for our happy little fish.
In this case, we could change the program to move x by 1 pixel at a time and then move y by 4/6 pixel at a time and thus go on a path straight towards the goal. If we were to increase the y by a full pixel, it would arrive directly below the target and then go straight up. This would be an indirect path and less realistic looking.
Actually I think it would arrive to the left of the goal and then go directly right in the old version if you use the 1 to 1 ratio, but I think you knew what I meant.
I'll try to adapt an example I have to your code:
int fishSpeed = 2;
float xOffset = fishSpeed;
float yOffset = fishSpeed;
float xDis = abs(this.xPos-(foodArray[index].x + foodWidth));
float yDis = abs(this.yPos-(foodArray[index].y + foodWidth));
//each offset changes depending on how far it is from goal
xOffset = xOffset * (xDis / (xDis + yDis));
yOffset = yOffset * (yDis / (xDis + yDis));
if(this.xPos > foodArray[index].x) this.xPos+=xOffset;
if(this.yPos > foodArray[index].y) this.yPos+=yOffset;
if(this.xPos < foodArray[index].x) this.xPos-=xOffset;
if(this.yPos < foodArray[index].y) this.yPos-=yOffset;
Sorry I couldn't make it work using your example. I don't know if it will help, but here is a complete .htm file that has a bunny wabbit that is controlled by the mouse and one that is chased directly by another wabbit. The wabbit will go directly for its goal. The file needs processing.js in the same directory.
<!DOCTYPE html>
<html>
<body bgcolor="lightblue" style="margin:0;">
<center>
<script src="processing.js"></script>
<script type="application/processing">
void setup(){
size(screen.width*.9,screen.height*.9);
blueWabbit = new wabbit(600,600,105);
pinkWabbit = new wabbit(100,100,100);
blueWabbit.blue = 255;
blueWabbit.red = 128;
blueWabbit.green = 128;
wabbitSpeed = 5;
}
void draw() {
float xOffset = wabbitSpeed;
float yOffset = wabbitSpeed;
float xDis = abs(pinkWabbit.xpos-blueWabbit.xpos);
float yDis = abs(pinkWabbit.ypos-blueWabbit.ypos);
xOffset = xOffset * (xDis / (xDis + yDis));
yOffset = yOffset * (yDis / (xDis + yDis));
if(pinkWabbit.xpos > blueWabbit.xpos) blueWabbit.xpos+=xOffset;
if(pinkWabbit.ypos > blueWabbit.ypos) blueWabbit.ypos+=yOffset;
if(pinkWabbit.xpos < blueWabbit.xpos) blueWabbit.xpos-=xOffset;
if(pinkWabbit.ypos < blueWabbit.ypos) blueWabbit.ypos-=yOffset;
if (xDis+yDis<wabbitSpeed){
for(int a =0;a<20; a++)babyWabbit();
}
else background(0,0,0,0);
pinkWabbit.show();
blueWabbit.show();
pinkWabbit.xpos = mouseX;
pinkWabbit.ypos = mouseY;
/*
fill(0);
text("blue x = "+(int)blueWabbit.xpos,10,10);
text("blue y = "+(int)blueWabbit.ypos,10,20);
text("pink x = "+pinkWabbit.xpos,10,30);
text("pink y = "+pinkWabbit.ypos,10,40);
text("xOffset = "+xOffset,10,50);
text("yOffset = "+yOffset,10,60);
text("xDis = "+(int)xDis,10,70);
text("yDis = "+(int)yDis,10,80);
*/
}
class wabbit {
//declare the properties that will be used as variables for the object
float xpos, ypos, diameter;
int red, blue, green;
//define the parameters for the creation of a new class
wabbit (float x, float y, float wSize) {
xpos = x;
ypos = y;
diameter = wSize;
//radius = .5 * diameter;
//make it pink if user did not define colors
if (!(0>red>256)) red = 255;
if (!(0>green>256))green = 200;
if (!(0>blue>256)) blue = 200;
}
void show() {
noStroke();
for(a = diameter; a > 0; a-=5){
fill(red-a,green-a,blue-a);
//belly and head
ellipse(xpos, ypos, a, a);
ellipse(xpos, ypos-diameter*.7, a*.7,a*.7);
//feets
ellipse(xpos-.2*diameter, ypos+diameter*.4, a*.4,a*.4);
ellipse(xpos+.2*diameter, ypos+diameter*.4, a*.4,a*.4);
//ears
ellipse(xpos-.2*diameter, ypos-diameter, a*.2,a*.8);
ellipse(xpos+.2*diameter, ypos-diameter, a*.2,a*.8);
}
}
}
void babyWabbit(){
noStroke();
var red=random(1,255);
var green=random(1,255);
var blue=random(1,255);
var xpos=random(1,width);
var ypos=random(1,height);
var diameter = random(20,80);
for(var a = diameter; a > 0; a-=5){
fill(red-a,green-a,blue-a);
//belly and head
ellipse(xpos, ypos, a, a);
ellipse(xpos, ypos-diameter*.7, a*.7,a*.7);
//feets
ellipse(xpos-.2*diameter, ypos+diameter*.4, a*.4,a*.4);
ellipse(xpos+.2*diameter, ypos+diameter*.4, a*.4,a*.4);
//ears
ellipse(xpos-.2*diameter, ypos-diameter, a*.2,a*.8);
ellipse(xpos+.2*diameter, ypos-diameter, a*.2,a*.8);
}
}
</script><canvas></canvas>
</body>
</html>
I am a novice who is working on a simple JavaScript web page that using the processing.js plugin to generated moving graphics. I have started to work on collision detection and handling. I examine each graphic and change it's direction if it gets too close to any of the other graphics. The program is buggy because the graphics eventually have simultaneous collisions on more than one other graphic. This then creates an interesting (but undesired) effect of getting the graphics "stuck" inside one another.
I could work on a function to detect multiple collisions and handle them in a way that stops the graphical objects from getting inside each other. However, I feel like their is a more fundamental flaw in my approach. I don't want to create a band aide solution when their may be a more structural flaw in my collision handling approach.
Should I just write a function that handles the bug of multiple simultaneous collisions or should I go back to the drawing board with program structure?
<!DOCTYPE html>
<html>
<body bgcolor="lightblue" style="margin:0;">
<center>
<script src="processing.js"></script>
<script type="application/processing">
int orbNumber = 30;
void setup(){
h=[];
float t;
size(600,600);
frameRate(60);
//assign starting variables for floating objects
for(int a = 0; a < orbNumber; a++){
h[a] = new orb(0, 200, 1, 64);
h[a].xpos = random(1,width);
h[a].ypos = a * 100;
h[a].red = random(128,255);
h[a].blue = random(128,255);
h[a].green = random(128,255);
}
}
void draw() {
background(200,200,200,0);
//call the update method from the orb class to calculate postion and display graphic
for(int a = 0; a < orbNumber; a++)h[a].update();
//number the graphics
textFont("Arial", 22);
fill(255,255,255,80);
for(int a = 0; a < orbNumber; a++)text(a,h[a].xpos-6,h[a].ypos+6);
//for each graphic, check distance for each other graphic and change
//movement direction upon collisions
for(int a = 0; a < orbNumber; a++)for(int b = a+1; b < (orbNumber); b++){
if(circleCollision(h[a],h[b])){
t=h[a].xOffset;
h[a].xOffset=h[b].xOffset;
h[b].xOffset = t;
t=h[a].yOffset;
h[a].yOffset=h[b].yOffset;
h[b].yOffset = t;
h[a].update;
h[b].update;
h[a].imperfectEdge()
h[b].imperfectEdge()
}
}
}
function circleCollision(circle1,circle2){
var x1 = circle1.xpos;
var x2 = circle2.xpos;
var y1 = circle1.ypos;
var y2 = circle2.ypos;
var distance = sqrt( (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2) );
var widths = circle1.radius + circle2.radius;
var t = false;
if(distance<widths)t = true;
//text("distance = " + distance,20,20);
return t;
}
class orb {
float xpos, ypos, speed, diameter, xOffset, yOffset, radius;
int red, blue, green;
orb (float x, float y, float s, float size) {
xpos = x;
ypos = y;
diameter = size;
xOffset = s;
yOffset = s;
radius = .5 * diameter;
}
void update() {
ypos += yOffset;
xpos += xOffset;
if(yOffset<0&&ypos<0+radius){
yOffset=-yOffset;
imperfectEdge();
}
if(yOffset>0&&ypos>height-radius){
yOffset=-yOffset;
imperfectEdge();
}
if(xOffset<0&&xpos<0+radius){
xOffset=-xOffset;
imperfectEdge();
}
if(xOffset>0&&xpos>width-radius){
xOffset=-xOffset;
imperfectEdge();
}
noStroke();
for(a = diameter; a > 0; a-=5){
fill(red-a,blue-a,green-a);
ellipse(xpos, ypos, a, a);
}
}
void imperfectEdge(){
xOffset=xOffset+random(-.1,.1);
yOffset=yOffset+random(-.1,.1);
}
}
</script><canvas></canvas>
</body>
</html>
I'm trying to replicate a game called haxball, which is a really simple and basic 2d football game. However I am having trouble on the collision detection and I didn't want to use a engine like Box2d because it's a bit of overkill for what I want and I'm making the game just to practice, since I'm a beginner.
I can check if the collision happens, but I can't resolve it properly. I loop through all objects and check if they are colliding with the ball and then, if they are, I put the ball at the "border" of the object so that it stops being "inside" the other.
The problem comes here, because if the ball collides with a circle and a edge at the same time it will stay inside the edge or inside the circle.
This is the code of collision resolving for the circle and detection and resolving of the edge:
this.resolveCollisionCircle = function(circle) {
var nv = circle.pos.sub(this.pos);
nv = nv.setMag(circle.radius + this.radius).add(circle.pos);
this.pos = nv;
// I'll try to add later the bounce effect
}
this.edgeCollision = function() {
if(this.pos.x-this.radius < 0) {
this.pos.x = this.radius;
this.velocity = this.velocity.mult(new Vector(-1, 1));
}
else if(this.pos.x+this.radius > Width) {
this.velocity = this.velocity.mult(new Vector(-1, 1));
}
if(this.pos.y-this.radius < 0) {
this.pos.y = this.radius;
this.velocity = this.velocity.mult(new Vector(1, -1));
}
else if(this.pos.y+this.radius > Height) {
console.log('baixo')
this.velocity = this.velocity.mult(new Vector(1, -1));
}
}
The ball moves accordingly to a velocity vector, in this case it starts as (-4,0)
Demo of the bug: http://antoniomc.0fees.us/
Also! If you could point me to a good canvas tutorial that could teach me this things, I would appreciate it! I only seem to find for another languages, which helped me anyway, but it would be nice to see a canvas collision detection and resolution tutorial once in a while...
In .resolveCollisionCircle(), store the old position, change the position, and revert back to the old position and stop the ball completely if the new position is outside of the canvas.
this.resolveCollisionCircle = function(circle) {
//previous position
var prevPos = this.pos;
//set new position
var nv = circle.pos.sub(this.pos);
nv = nv.setMag(circle.radius + this.radius).add(circle.pos);
this.pos = nv;
//change back if out of canvas
if ((this.pos.x-this.radius < 0) || (this.pos.x+this.radius > Width) || (this.pos.y-this.radius < 0) || (this.pos.y+this.radius > Height)) {
this.pos = prevPos;
this.velocity = this.acceleration = new Vector(0, 0);
}
}