how do I loop squares in a diagonal row in p5.js - loops

I need to loop 9 squares in a diagonal row with small spaces in between. I'm not sure how to do this.
I've done it with circles before, but the code I used for circles is not working with squares

let boxA;
let curBox;
function setup()
{
createCanvas(800, 800);
stroke(255);
strokeWeight(3);
noFill();
boxA = [];
curBox = createVector(0,0);
}
function draw()
{
background(0);
for(let i = 0; i < 9; i++)
{
boxA.push(new Box(curBox.x,curBox.y));
curBox = p5.Vector.fromAngle(QUARTER_PI, (i+1) * 90);
boxA[i].show();
}
}
class Box
{
constructor(x,y)
{
this.x = x;
this.y = y;
}
show()
{
rect(this.x,this.y, 50,50);
}
}
I think this is what you're asking for. Idk, tbh. you were very vague with your question.
This code will start at 0,0 (the top left) and using p5.Vector.fromAngle, it makes a new vector from 0,0 to a new point given an angle and distance.
it then makes a new box at that new point. Simply repeat the cycle for all nine.

Related

Image array p5.js

I've created some nested arrays to display array of Images, one thing I cant get right it repeats the same image instead of drawing a new one in every loop.
here is my example code simulates my problem
var images = [];
function preload() {
for (var i = 0; i< 3; i++) {
images[i] = loadImage("img/img" + i + ".jpg");
}
}
function setup() {
createCanvas(900, 900);
background(0);
preload();
}
function draw() {
//image(images[0],0,0);
for ( var y= 0; y < height; y=y+300) {
for ( var x =0; x < width; x=x+300) {
for ( var z = 0; z < 3; z++) {
image(images[z], x, y );
}
}
}
}
as images, i just used 300x300 jpgs 3 of them to test out.
I might be wrong, but quickly reading through your code, it looks you're drawing 3 images on top of each other:
image(images[z], x, y );
You can add console.log(x,y); before or after that line to double check.
Overall you're doing a grid, where you might want each element of that grid to be the images you preloaded, but you need to space them out a bit:
image(images[z], x + images[z].width * z, y );
This is quick and hacky, but you can actually work out how much spacing you need: total width / (image width + image spacing) = spacing per image, assuming the loaded images are the same size
Another option might be to cycle through the images from the array:
function draw() {
var i = 0;
//image(images[0],0,0);
for ( var y= 0; y < height; y=y+300) {
for ( var x =0; x < width; x=x+300) {
//using % to loop back to the first element after the array length
image(images[i % images.length], x, y );
i++
}
}
}
Note that the above code hasn't been tested, but hopefully it will be understandable enough to adapt

Processing - Animation between two points

I am developing the below code. To give you a brief description, it is allowing the user to click on different points on the screen, then these mouse coordinates and positions are stored in an array and also seen on the screen. When the user clicks enter there is a movement from the first point to the last point, using the linear interpolation technique. I am having difficulty in the for loop as the PVector v is storing the coordinates. Could anyone please guide me accordingly?.
ArrayList vectors;
PVector v = new PVector();
boolean animate = false; //declare a boolean variable you can use to switch from building points to animating the movement
int FirstMouseClick; //declare an int variable to store the frameCount of the first mouseclick
int AnimationStart; //declare an int variable to store the frameCount of the animation start
void setup()
{
size(500, 500);
frameRate(60);
vectors = new ArrayList();
}
void draw()
{
if(!animate)//if the boolean variable animate is true
{
float output = frameCount - AnimationStart; // subract the animation start frameCount from the current frameCount so you know which framecount from the vectors array you should be showing
for(int i=0; i<vectors.size(); i++) //loop through the vectors array
//until you find the (next PVector's frameCount - frameCount of first mouseClick) > above subtraction result
{
v = (PVector)vectors.get(frameCount); //until you find the (next PVector's frameCount)
}
ellipse(v.x,v.y,10,10);// use the current pvector's xpos and ypos to draw the ellipse
}
}
void mouseClicked()
{
frameCount = 0; //if not yet set, set the first frameCount value
vectors.add(new PVector(mouseX, mouseY,frameCount));// <--- store the framecount in the z axis
ellipse(mouseX,mouseY,10,10);
println("Mouse Coordinates are: " + vectors);
}
void keyPressed()
{
if(keyCode == ENTER)
{
animate = true; //set the boolean variable animate to true
AnimationStart = 3; //set the framecount of the animation start
}
}
I'm really not sure, what you were trying to do, but if I got you right you want to do something like this:
Draw some circles, if user clicked on canvas
If user pressed Enter, start animation
Animation means: another circle (v) moves linear from circle to circle
I really don't know, what your frameCount was for. May be you can add it to this code easier now? Note, that you can add new targets by clicking with the mouse, even if animation is true.
You can do this:
ArrayList<PVector> vectors = new ArrayList();
PVector v = new PVector();
boolean animate = false; // true means, the circles moves
int nextTarget = 0; // defines the index of the next circle, the point is going to
void setup()
{
size(500, 500);
frameRate(60);
v = new PVector(width/2, height/2);
}
void draw() {
// draw background to delete old drawings
background(128);
// show all circles
for (int i=0; i<vectors.size(); i++) {
fill(255);
ellipse(vectors.get(i).x, vectors.get(i).y, 10, 10);
}
// if the boolean variable animate is true
if (animate) {
// compute angle to target circle and remaining distance
float diffX = vectors.get(nextTarget).x - v.x;
float diffY = vectors.get(nextTarget).y - v.y;
float angle = atan2(diffX, diffY);
// defines the speed of the circle
float movement = 2;
// compute new position of v
v = new PVector(v.x + sin(angle)*movement, v.y + cos(angle)*movement);
// if v reached the target circle, move on to the next one
if (dist(v.x, v.y, vectors.get(nextTarget).x, vectors.get(nextTarget).y) < 1 && nextTarget < vectors.size()-1) {
nextTarget++;
}
}
fill(0);
ellipse(v.x, v.y, 10, 10); // use the current pvector's xpos and ypos to draw the ellipse
}
void mouseClicked()
{
vectors.add(new PVector(mouseX, mouseY));
ellipse(mouseX, mouseY, 10, 10);
println("Mouse Coordinates are: " + vectors);
}
// toggle animation mode
void keyReleased() {
if (key == ENTER) {
animate = !animate;
println("animation: "+ animate);
}
}

Interpolation function in processing

I am new new to processing and I am trying to experiment with the lerp function in processing. Basically what I am trying to do is, click on different point on the screen, these positions are being stored in an array. when the user clicks enter, the stored movements are replayed with an ellipse moving smoothly between the points. My problem is that when I click enter, I am getting the 'Arithmetic exception by zero'. Can you please guide me what I am missing? Thanks.
final static int numFrames = 30; //frames between keyframes
final static int numKeyFrames = 1; //frames between keyframes
Point[] keyFrames;
Point[] frames;
void setup()
{
size(640, 480);
frameRate(30);
LinearInterp();
}
void mouseClicked()
{
stroke(0);
strokeWeight(8);
for(int i=0; i<numKeyFrames; i++)
{
keyFrames = new Point[numKeyFrames];
keyFrames[i] = new Point(mouseX,mouseY);
point(keyFrames[i].x,keyFrames[i].y);
println("Mouse Coordinates are: " + keyFrames[i]);
}
}
void LinearInterp()
{
frames = new Point[numFrames*(numKeyFrames-1)];
for (int kf = 0; kf< numKeyFrames-1; kf++)
{
Point p0 = keyFrames[kf];
Point p1 = keyFrames[kf+1];
for (int f =0; f<numFrames; f++)
{
float a = f*1.0/numFrames;
int newX = int(p0.x * (1-a) + p1.x * a);
int newY = int(p0.y * (1-a) + p1.y * a);
frames[f+(kf*numFrames)] = new Point(newX,newY);
}
}
}
void animateFrames()
{
stroke(187);
strokeWeight(10);
int i = frameCount % frames.length;
point(frames[i].x,frames[i].y);
}
void drawFrames()
{
stroke(187);
strokeWeight(2);
for (int i=0; i<frames.length; i++)
{
point(frames[i].x,frames[i].y);
}
}
void draw()
{
if(keyPressed)
{
if(key == ENTER)
{
drawFrames();
animateFrames();
}
}
}
Why did you delete your last question? Please don't delete questions after somebody takes the time to answer them.
Like I said in your last question, you need to store the index of which "leg" of the journey you're on. You also need to store how far along that leg the point should be. When you reach the next point, then increment the index and reset the percentage.
In any case, you need to break this problem down into smaller steps. Can you create a program that shows a circle travelling from one hard-coded point to another? Start with that, without worrying about user input. Get that working perfectly before moving on. Then get a program working that shows a circle moving from a hard-coded point to a point the user clicks. Get that working perfectly. Then get a program that shows a circle moving between two user clicks. Get that working perfectly. Notice a pattern?

How do I interact with a grid using a 2D array (Proce55ing)

For a project I need to create Connect Four using Processing, I have created the grid which the game will be played in however I am lost when it comes to players interacting with it.
I have been told to use a 2D array however my knowledge of arrays is very limited. I am currently trying to code the bit where the program detects where a player has clicked and spawning a coin there.
int c = 8;
int r = 10;
int[][] grid = new int [c][r];
int CoinSpawn = -1;
void setup () {
size(1000, 800);
}
void draw () {
background(1, 1, 1);
translate(100, 100);
noStroke();
drawColumns();
drawRows();
}
void keyPressed () {
for (int i=0; i<grid.length-1; i++) {
grid[i][i] = grid[i+1][i+1];
}
}
void drawRows(){
for (int i=0; i < r; i++){
int x = 80;
x = x * i;
translate(x,0);
drawColumns();
translate(-x,0);
}
}
void drawColumns(){
for (int i=0; i < c; i++){
int y = 80;
y = y * i;
translate(0,y);
drawCell();
translate(0,-y);
}
}
void drawCell(){
fill(0,0,255);
rect(0,0,80,80);
noFill();
fill(0);
ellipseMode(CENTER);
translate(40,40);
ellipse(0,0,75,75);
noFill();
translate(-40,-40);
}
Would I be able to assign the 2D array to the grid? so that each slot in the grid represents an element from the array? That is the best option I can see at the moment however I have no idea how to do it.
I really appreciate any replies as I am completely lost at the moment.
You have a pretty good start, I made a lot more changes than I had planned... got a little into it!
Let me know if you have any questions, I did use one simple OOP class called cell that tracks the value and the cell's position, as well as provides a display function, I converted a lot of your variables and hard coded numbers to constants (starts with final and has the same value for the entire program)
you will notice I left the win conditions to you!
I hope this is helpful, I feel like seeing 2D arrays used in a context you are familiar with might help you understand them!
My normal process using 2D arrays for processing:
use Setup() to set initial array values
use Draw() to call each of the item's display function
use other functions to modify the array data, which the display function of the cell knows how to display
Main File
// Grid Size constants
final int GRID_COLUMNS = 10;
final int GRID_ROWS = 8;
// Display constants
final int CELL_SCALE = 80;
final int COIN_RADIUS = 75;
final int BOARD_PADDING = 100;
final color[] PLAYER_COLORS = new color[]{color(0), color(200, 10, 10), color(200, 200, 10)};
// cell values
final int EMPTY_CELL = 0;
final int PLAYER_1 = 1;
final int PLAYER_2 = 2;
// game data
Cell[][] grid = new Cell [GRID_COLUMNS][GRID_ROWS];
int currentPlayer;
void setup () {
size(1000, 800);
ellipseMode(CENTER); // only needs to be set once per sketch
setupBlankBoard();
}
// method to populate the array with blank cells, used to initiate and reset the game
void setupBlankBoard() {
currentPlayer = PLAYER_1; // reset game and start with first player
// populate array
for (int y=0; y < GRID_ROWS; y++) { // for every vertical row,
for (int x=0; x < GRID_COLUMNS; x++) { // for every horizontal cell in that row
// rather than translates I prefer to calculate the actual x,y position and just display it there,
// we add the padding offset to every cell, and then take the column/row times the width of the square cell
grid[x][y] = new Cell(BOARD_PADDING+x*CELL_SCALE, BOARD_PADDING+y*CELL_SCALE);
}
}
}
void changePlayers() {
if (currentPlayer == PLAYER_1) {
currentPlayer = PLAYER_2;
} else {
// already was player 2, so change to 1
currentPlayer = PLAYER_1;
}
}
boolean placeCoin(int column) {
boolean coinPlaced = false;
// now we know the column, we need to find the lowest cell in that column that is empty
for (int y = GRID_ROWS-1; y >= 0; y-- ) { // let's start at bottom and move up to reduce computations
// for every cell, test if it is empty
if (grid[column][y].isEmpty()) {
// if found a valid cell, place current players token and exit the loop (break)
grid[column][y].setValue(currentPlayer);
coinPlaced = true;
break;
}
}
return coinPlaced;
}
void checkCoins() {
// scan the array for 4 of the same value in a row
for (int y=0; y < GRID_ROWS; y++) { // for every vertical row,
for (int x=0; x < GRID_COLUMNS; x++) { // for every horizontal cell in that row
//grid[x][y]
// I will leave this to you ;)
// keep in mind to check neighbors all you need to do is add or subtract 1 from the x or y value
// however when you are at the edge of the board be careful not to try and look at a neighbor that is off the edge, you will get a null pointer or an array out of bounds exception
if (x+1<GRID_COLUMNS) {
Cell toTheRight = grid[x+1][y];
}
// for each cell you could look at the 3 above the current, 3 below the current, 3 to the right and 3 to the left, 3 diagnal in each direction and then manually try and find 4 adjacent same color cells
// or a bit more complicated is a recursive solution that checks its 8 immediate neighbor and for each that match the center cell run the same function to test its 8 neighbors keeping track of the current inARowCount and returning true when it is found.
// would be a bit hard because you would need to make sure the second cell doesn't follow back to the original cell, and start an endless loop
}
}
}
void draw () {
background(1, 1, 1);
noStroke();
// draw all cells
for (int y=0; y < GRID_ROWS; y++) { // for every vertical row,
for (int x=0; x < GRID_COLUMNS; x++) { // for every horizontal cell in that row
grid[x][y].display(); // draw this cell
}
}
// draw next coin floating above the board, contrain its positon to above the board
fill(PLAYER_COLORS[currentPlayer]);
int currentMouseX = constrain(mouseX, BOARD_PADDING+COIN_RADIUS/2, BOARD_PADDING+(GRID_COLUMNS*CELL_SCALE)-COIN_RADIUS/2);
//currentMouseX = 40*(ceil(abs(currentMouseX/40)));
ellipse(currentMouseX, BOARD_PADDING/2, COIN_RADIUS, COIN_RADIUS);
}
// press any key to rest the game, probably want to test for a certain key here!
void keyPressed () {
setupBlankBoard();
}
// on press attempt to place a coin
void mousePressed() {
int currentMouseX = constrain(mouseX, BOARD_PADDING+COIN_RADIUS/2, BOARD_PADDING+(GRID_COLUMNS*CELL_SCALE)-COIN_RADIUS/2);
// determine what column we are over
int column = (currentMouseX - BOARD_PADDING)/CELL_SCALE;
// if choice is a valid coin placement
if (placeCoin(column)) {
// toggle players if a coin was placed
changePlayers();
// after each placement check win conditions
checkCoins();
}
}
Cell Class
class Cell {
int x, y;
int value; // 0 for empty, 1 for team 1, 2 for team 2 (constants defined at top of main file)
Cell(int x, int y) {
// default constructor to create empty cell
this(x, y, EMPTY_CELL);
}
// allows cell value to be set at creation
Cell(int x, int y, int value) {
this.x = x;
this.y = y;
this.value = value;
}
boolean setValue(int value){
value = constrain(value, EMPTY_CELL,PLAYER_2); // keeps it from setting a value outside of our range
if(this.value == EMPTY_CELL){
this.value = value;
return true; // placed
}
return false; // was not able to place it as there is already a value
}
boolean isEmpty(){
return this.value == EMPTY_CELL;
}
void display() {
fill(0, 0, 255);
rect(this.x, this.y, CELL_SCALE, CELL_SCALE);
// Draw Circle color based on current value, could simply just put fill(playerColors[this.value]); but this seems a bit more clear
if(this.value == EMPTY_CELL){
fill(PLAYER_COLORS[EMPTY_CELL]);
}else if(this.value == PLAYER_1){
fill(PLAYER_COLORS[PLAYER_1]); // red
}else if(this.value == PLAYER_2){
fill(PLAYER_COLORS[PLAYER_2]); // yellow
}
ellipse(this.x + CELL_SCALE/2, this.y + CELL_SCALE/2, COIN_RADIUS, COIN_RADIUS);
}
}

Have object rotate another object in array?

Hey everyone so I have an object character that initially rotates around the first Movie Clip called planet which isn't apart of the array. So the user can tap the screen and the character shoots in direction it is rotating. The objective is to have the character hit the other planets in a array and when it does have it start rotating around it just like the original. Everything works fine except when I shoot the character and it lands on one of the outerplanets in aPlanetArray it doesn't start rotating around that new planet but rather just disappears.
Here is how I set it up:
character Orbits first planet that is not in the array just have it as intial orbit then remove it once leaves to other outerPlanets:
private function startOrbit():void
{
//add Planet
planet.x = (stage.stageWidth / 2);
planet.y = (stage.stageHeight / 2) + 100;
stage.addChild(planet);
//radnom number set up in main class
if (randomOrbit == 1) //If equals to one then clock wise
{
clockWiseOrbiter();
}else
if (randomOrbit == 2) //If equals to one then counter clock wise
{
counterClockWiseOrbiter();
}
}
I add outer Planets in array:
private function addOuterPlanets():void
{
for (var i:int = 0; i < nPlanets; i++)
{
outerPlanets = new mcOuterPlanets();
outerPlanets.x = startPoint.x + (xSpacing * i);
outerPlanets.y = startPoint.y - (ySpacing * i);
stage.addChild(outerPlanets);
aPlanetArray.push(outerPlanets);
}
}
In my Enter Frame Handler:
private function logicHandler(e:Event):void
{
if (!tap && !nextlevel)
{
startOrbit(); //start player orbit around planet
}
if (nextlevel)
{
startNewOrbit();
trace("Starting new Orbit");
}
//When tapped have outher planets move down
if (tap)
{
characterTap(); //Character shoots from position
}
collisionPlanetHandler();
}
When the collision happens with Outer Planets:
**** EDIT*****
private function collisionPlanetHandler():void
{
for (var i:int = 0; i < aPlanetArray.length; i++)
{
var currentPlanet:mcOuterPlanets = aPlanetArray[i];
if (character.hitTestObject(currentPlanet[i]) && !nextlevel)
{
trace("HIT");
//Have charcter orbit that planet
//startNewOrbit();
//tap back to false
tap = false;
nextlevel = true;
character.destroy();
planet.destroy();
planetHit = currentPlanet[i];
}
}
}
When the character collides with the outerPlanets in array I have the New orbit happen around the OuterPlanet it lands on. Or I at least try:
private function startNewOrbit():void
{
newClockWise();
}
private function newClockWise():void
{
for (var i:int = 0; i < aPlanetArray.length; i++)
{
var currentPlanet:mcOuterPlanets = aPlanetArray[i];
stage.addChild(character);
character.rotation = (Math.atan2(character.y - currentPlanet.y, character.x - currentPlanet.x) * 180 / Math.PI);
var rad:Number = angle * (Math.PI / 180); // Converting Degrees To Radians
character.x = currentPlanet.x + radius * Math.cos(rad); // Position The Orbiter Along x-axis
character.y = currentPlanet.y + radius * Math.sin(rad); // Position The Orbiter Along y-axis
angle += speed; // Object will orbit clockwise
}
}
I know I am doing something wrong in the startNewOrbit and newClockWise functions. I have a for loop and I am trying to target the object in array it touches. I use this var currentPlanet:mcOuterPlanets = aPlanetArray[i]; But not sure if I need to use currentObject or something equivalent. Does anyone have any idea what i am doing wrong why its not orbiting the new planet it touches but rather just disappears completely?
var planetHit:MovieClip;
function collisionTest():void{
for (loop through planets){
if (planet[i].hitTestObject(character)){
planetHit = planet[i];
}
}
}
See now the planet at that location in the array is (==) planetHit so then you can do
character.x = planetHit.x;
or
planetHit.addChild(character);
etc.

Resources