For my class, I'm creating a project in which a level includes a cursor in the form of an ellipse that reacts to a mousePressed command by having spikes protrude from within the ellipse and then recede back into the ellipse.
The code for my cursor is right here:
class Cursor{
float r;
float x;
float y;
Cursor(float _r){
r = _r;
x = 0;
y = 0;
}
void setLocation (float _x, float _y) {
x = _x;
y = _y;
}
void display(){
noStroke();
fill(230, 242, 255);
ellipse(x, y, r, r);
}
My teacher suggested I use createShape (TRIANGLE) within the ellipse and animate one of the vertices from each spike coming out at the appropriate time, but I simply wasn't able to follow his instructions as well as I had needed to.
Any assistance on this matter would be greatly appreciated. I do hope to further use the animated vertices to "pop" a surrounding object later on, but I'm only mentioning that in the case that it's important for the initial creation and animation.
Thank you very much in advance!
Your teacher was probably talking about the beginShape(TRIANGLES) function. From the reference:
beginShape(TRIANGLES);
vertex(30, 75);
vertex(40, 20);
vertex(50, 75);
vertex(60, 20);
vertex(70, 75);
vertex(80, 20);
endShape();
(source: processing.org)
You could use this function to generate your spikes around your circle. You'll have to figure out the x and y positions of the triangles around the circle, but you can do that using an incrementing angle and the cos() and sin() functions.
Related
By default, it seems like a sphere object in P5 is located at (0,0). I want to create an object that is visually represented by a sphere with the ability to define the x and y coordinates of the sphere object.
Because I want to deal with multiple of these objects and draw connections between them, I don't want to use the translate function for a sphere to position it every time. Is there a way to position the sphere to the coordinates I want without the translate function?
You can still use translate() without affecting the global coordinate system by isolating local coordinate systems within push()/pop() calls. You can read more in the 2D Transformation tutorial. Even through it's for Processing, the only difference is swapping pushMatrix() for push() and popMatrix() for pop() and the concept translates to 3D as well, not just 2D.
function drawSphere(x, y, z, radius){
push(); // enter local coordinate system
translate(x, y, z);
sphere(radius);
pop(); // exit local coordinate system (back to global coordinates)
}
Here's a basic example drawing multiple spheres and lines between them:
const NUM_POINTS = 12;
let points = new Array(NUM_POINTS).fill();;
function setup(){
createCanvas(600, 600, WEBGL);
noFill();
// shorthand for initialising 12 random points at a set distance
points.forEach((p,i) => points[i] = p5.Vector.random3D().mult(150));
}
function draw(){
background(255);
rotateY(frameCount * 0.01);
// draw spheres (and lines from centre)
for(let i = 0 ; i < NUM_POINTS; i++){
// get each point
const point = points[i];
// draw sphere
drawSphere(point.x, point.y, point.z, 30);
// draw lines (optional)
const nextPoint = points[(i + 1) % NUM_POINTS];
line(nextPoint.x, nextPoint.y, nextPoint.z, point.x, point.y, point.z);
}
}
function drawSphere(x, y, z, radius){
push(); // enter local coordinate system
translate(x, y, z);
sphere(radius, 6);
pop(); // exit local coordinate system (back to global coordinates)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.min.js"></script>
(If you're familiar with 3D packages such as Blender, C4D, Maya, etc. most of these allow you to nest an object inside another object (inheriting the parent's transformation, but allowing indepedent transformations which don't affect the parent. This is roughtly what you can achieve with push()/pop() calls).
function createSphere(x, y, z, r) {
translate(x, y, z)
sphere(r)
}
usage
createSphere(1, 2, 3, 10)
For school, I need to make a game, so I had the idea of making a game similar to, "magic touch:wizard for hire", which is a game where balloons fall out of the sky, and you need to make drawings to pop them, that's the idea I'm going for.
But now, my problem:
I had the idea of making balloons appearing randomly through the x axis,(so it would always spawn at the y=0 and the x axis be random),but that's where my problem's at. I made tree functions for it:
This is the function that creates the random number:
function aleatorizar() {
let random= Math.floor(Math.random()*canvas.width);
return random;
}
This is the function that draws the balloons with text on them:
function desenharbombas(x){
ctx.beginPath();
ctx.arc(x,posição,50,0,2*Math.PI);
ctx.stroke();
ctx.fillStyle= "#000000";
ctx.fill();
function escrever(){
ctx.font="17px Arial Black";
ctx.fillStyle="#ffffff";
ctx.fillText("texto",x,posição );
}
escrever()
}
And this is the function that animates the balloons falling down:
function animar(y){
ctx.clearRect(0,0,canvas.width,canvas.height);
posição=posição+1;
desenharbombas(y)
requestAnimationFrame(animar);
}
In my logic (and trough hours of testing), I cannot put the random function inside my bomb drawing function, because it will make the random function change every time the drawing function is called, so that'd make the bombs glitch left and right on the screen.
So I created this logic, which the bomb drawing function would only receive a random number, when the animate function was called, but it didn't work, because now the bomb is falling diagonally. I know it's really hard to understand, but if anyone knows how to help or wants to hop on discord to help me...(caue#7600)
How about something like this:
const canvas = document.getElementById("c");
const ctx = canvas.getContext("2d");
ctx.textAlign = 'center';
ctx.textBaseline = 'middle'
var bombas = []
class bomba {
constructor(name, x, y, speed, radius) {
this.name = name
this.x = x
this.y = y
this.speed = speed
this.radius = radius
}
draw() {
ctx.beginPath();
ctx.arc(this.x += this.speed, this.y, this.radius, 0, 2 * Math.PI);
ctx.stroke();
ctx.fillText(this.name, this.x, this.y);
}
}
function aleatorizar() {
return Math.floor(Math.random() * canvas.width);
}
bombas.push(new bomba("A", aleatorizar()/4, 10, 0.20, 8))
bombas.push(new bomba("B", aleatorizar()/4, 40, 0.25, 12))
bombas.push(new bomba("C", aleatorizar()/4, 70, 0.15, 10))
function animar() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
bombas.forEach(b => b.draw())
requestAnimationFrame(animar);
}
animar()
<canvas id="c"></canvas>
You can see that we have a class bomba and on the constructor we pass all the initial parameters needed to draw what we need, then in the draw() function we increase the value of the x by the given speed, and draw the arc and the text.
With this new class you can add more random parameters, right now it is just the Y that is random but on that same way you can do it for the speed and also the radius
And if you really want to build a game you should look into game engines, there are many good Open Source, github has a nice collection of well known:
https://github.com/collections/javascript-game-engines
As your game gets more complex you are going to run into problems that are already solved in a game engine, it just depends how far do you want to go with this game
i am making a javascript shooter game.i want the the player to rotate towards the mouse.it is working, but the rotation was not correct.
I tried this with an image, and it works, but with the sprite itself(player1), is not.
i have asked this once before but received no answer
I am a beginner in javascript, so help would be appreciated.
I am using the p5.js libraries
Here is my code snippet:
//variables
var player1;
var gun1;
var gun2;
function preload(){
img = loadImage('rect1.png');
}
function setup(){
//creating sprites
player1 = createSprite(200,200,30,30)
gun = createSprite(player1.x,player1.y-20,5,30)
gun.shapeColor = "black"
player1.addImage("player",img)
player1.scale = 0.2
}
function draw(){
canvas = createCanvas(displayWidth-20, displayHeight-120);
background("#32CD32");
push()
gun.x = player1.x;
gun.y = player1.y-15;
// functions to move
//up
if(keyDown("up")){
player1.y = player1.y - 5;
}
//down
if(keyDown("down")){
player1.y = player1.y + 5;
}
//right
if(keyDown("right")){
player1.x = player1.x + 5;
}
//left
if(keyDown("left")){
player1.x = player1.x - 5;
}
angleMode(DEGREES)
imageMode(CENTER)
let a = atan2(mouseY - height / 2, mouseX - width / 2);
translate(width/2, height/2);
//rotate(a)
player1.rotation = a
//image(img,0,0,40,40)
pop()
drawSprites();
}
I think I'm using a dated version of p5.play, so there's not much in your code that works for me, but here's what I think is going on based on what you're saying.
If you want to understand what the deal is with atan2(), you first have to understand atan(). Basically, you have the ordinary trig functions sin, cos, and tan. Then you have the inverse trig functions arcsin, arccos, and arctan (abbreviated asin, acos, and atan). The arctan function is useful because you can input a slope and it will give you the angle of that slope. There's a catch, though; atan will only give values between -pi/2 and pi/2. This covers all non-vertical lines, but what if you wanted to use it for a vector or something that has direction? atan2() solves that problem. Instead of taking one input (a ratio: rise/run), it takes two inputs, a rise and a run. This prevents dividing by zero (for vertical lines) and signs of rise and run cancelling. The first input is the rise, and the second is the run. The output is the angle between the vector with those coordinates and the x-axis. So atan2() will give you some angle between -pi and pi.
Now let's look at what you have put into the atan2() function:
atan2(mouseY - height / 2, mouseX - width / 2);
So the vector you're considering is the vector from the middle of the canvas to the mouse. If this is what you want, great. If it's not, maybe consider
atan2(mouseY - player1.y, mouseX - player1.y);
which yields the "heading" (not really the heading) of the vector from the player's position to the mouse.
There are a couple of other potential problems (I can't figure out which one it is because p5.play isn't behaving, or I'm doing something else wrong):
radians/degrees: sometimes this stuff goes wrong. Try printing a and seeing if it's what you're looking for. If it's in degrees, consider saying player1.rotation = radians(a) instead. I know that p5.Vector.fromAngle() doesn't care about angleMode, maybe sprite.rotation doesn't either?
I don't know how drawSprites works, but you might consider putting it inside of the push()/pop() section. When drawing other shapes, this is how you get a rotation about the point (x, y):
let x = 100;
let y = 200;
let a = atan2(mouseY - y, mouseX - x);
push();
translate(x, y);
rotate(a);
square(-10, -10, 20);
pop();
The square is centered at (x,y), and is rotated about (x,y) toward the cursor. It's necessary that you do it in this order: push, translate, rotate, shape, pop. If you mix up that order, it doesn't do it right. But what you have is push, translate, pop, shape. I don't know how sprite.rotate works, so maybe it's supposed to do what you want. But here is another way to do a rotation. (If you're going to do it this way, I think you'd have to draw player1 "at (0,0)" after the translation and rotation, before pop)
I hope this helped!
I am trying to move an object smoothly from point A to point B using HTML canvas and regular javascript.
Point A is a set of coordinates
Point B is in the case the cursor location.
I made a jsfiddle of what I have so far: https://jsfiddle.net/as9fhmw8/
while(projectile.mouseX > projectile.x && projectile.mouseY < projectile.y)
{
ctx.save();
ctx.beginPath();
ctx.translate(projectile.x, projectile.y);
ctx.arc(0,0,5,0,2*Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
ctx.stroke();
ctx.restore();
if(projectile.mouseX > projectile.x && projectile.mouseY < projectile.y)
{
var stepsize = (projectile.mouseX - projectile.x) / (projectile.y - projectile.mouseY);
projectile.x += (stepsize + 1);
}
if(projectile.mouseY < projectile.y)
{
var stepsize = (projectile.y - projectile.mouseY) / (projectile.mouseX - projectile.x);
projectile.y -= (stepsize + 1);
}
}
Essentially what I can't figure out to do is to make the while loop slower (so that it appears animated in stead of just going through every iteration and showing the result).
I also can't figure out how to prevent the Arc from duplicating so that it creates a line that is permanent, instead of appearing to move from point a to point b.
Smooth animation here is really about determining how far to move your object for each iteration of the loop.
There is a little math involved here, but it's not too bad.
Velocity
Velocity in your case is just the speed at which your particles travel in any given direction over a period of time. If you want your particle to travel 200px over the course of 4 seconds, then the velocity would be 50px / second.
With this information, you can easily determine how many pixels to move (animate) a particle given some arbitrary length of time.
pixels = pixelsPerSecond * seconds
This is great to know how many pixels to move, but doesn't translate into individual X and Y coordinates. That's where vectors come in.
Vectors
A vector in mathematics is a measurement of both direction and magnitude. For our purposes, it's like combining our velocity with an angle (47°).
One of the great properties of vectors is it can be broken down into it's individual X and Y components (for 2-Dimensional space).
So if we wanted to move our particle at 50px / second at a 47° angle, we could calculate a vector for that like so:
function Vector(magnitude, angle){
var angleRadians = (angle * Math.PI) / 180;
this.magnitudeX = magnitude * Math.cos(angleRadians);
this.magnitudeY = magnitude * Math.sin(angleRadians);
}
var moveVector = new Vector(50, 47);
The wonderful thing about this is that these values can simply be added to any set of X and Y coordinates to move them based on your velocity calculation.
Mouse Move Vector
Modeling your objects in this way has the added benefit of making things nice and mathematically consistent. The distance between your particle and the mouse is just another vector.
We can back calculate both the distance and angle using a little bit more math. Remember that guy Pythagoras? Turns out he was pretty smart.
function distanceAndAngleBetweenTwoPoints(x1, y1, x2, y2){
var x = x2 - x1,
y = y2 - y1;
return {
// x^2 + y^2 = r^2
distance: Math.sqrt(x * x + y * y),
// convert from radians to degrees
angle: Math.atan2(y, x) * 180 / Math.PI
}
}
var mouseCoords = getMouseCoords();
var data = distanceAndAngleBetweenTwoPoints(particle.x, particle.y, mouse.x, mouse.y);
//Spread movement out over three seconds
var velocity = data.distance / 3;
var toMouseVector = new Vector(velocity, data.angle);
Smoothly Animating
Animating your stuff around the screen in a way that isn't jerky means doing the following:
Run your animation loop as fast as possible
Determine how much time has passed since last time
Move each item based on elapsed time.
Re-paint the screen
For the animation loop, I would use the requestAnimationFrame API instead of setInterval as it will have better overall performance.
Clearing The Screen
Also when you re-paint the screen, just draw a big rectangle over the entire thing in whatever background color you want before re-drawing your items.
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
Putting It All Together
Here is a Fiddle demonstrating all these techniques: https://jsfiddle.net/jwcarroll/2r69j1ok/3/
What I am trying to do is to make the white square to move around the canvas when the mouse is pressed with the mouse locations but it is not working. I know that I am missing something and ask you to help me. Here is my code:
Object o;
int[][] back =new int[3][3];
int pad = 10, bs=100; //len=pad*(back.length+1)+bs*back.length; za dinamichno resaizvane na ekrana
boolean drag = false;
void setup() {
size(400, 400);
noStroke();
o = new Object();
}
void draw() {
rectt(0, 0, width, height, color(100));
for (int row=0; row<back.length; row++)
for (int coll=0; coll<back[row].length; coll++) {
float x = pad+(pad+bs)*coll;
float y = pad+(pad+bs)*row;
rectt(x, y, bs, bs, color(150));
if (mouseX >=x && mouseX<=x+width/x*coll+bs
&& mouseY>=y && mouseY<=y+height/y*row+bs) {
rectt(x, y, bs, bs, color(255, 0, 0));
}
}
o.show();
//o.over();
}
void rectt(float x, float y, float w, float h, color c) {
fill(c);
rect(x, y, w, h);
}
void mousePressed() {
o.drag();
}
and the class is here:
class Object {
float size = 50;
float x;
float y;
// boolean d = false;
Object() {
x = width -60;
y = height -60;
}
void show() {
fill(255);
rect(x, y, size, size);
}
void drag() {
if ( mouseX >= x && mouseX <= x+size && mouseY <= y+size && mouseY >= y && mousePressed ) {
x = mouseX;
y = mouseY;
}
}
}
In the future, please tell us exactly what your code does, and exactly what you mean when you say it isn't working.
But let's run through your code and figure out what's going on.
First off, it's a pretty bad idea to name your class Object. It probably won't actually hurt anything, especially using Processing.js, but better safe than sorry. So I'm going to rename it to Rectangle.
After that, your main problem comes from the fact that you have two sets of x and y coordinates. The first come from your loop:
float x = pad+(pad+bs)*coll;
float y = pad+(pad+bs)*row;
You use this first set of coordinates to draw your rectangles. But then you have a second set of coordinates inside your Rectangle class:
x = width -60;
y = height -60;
You use this second set in your dragging logic, but then you never use them for drawing your rectangles. More generally, you never seem to use the show() function at all. Where do you expect that rectangle to show up?
Also, you only ever instantiate one Rectangle instance. The rectangles you're drawing in the for loop don't have anything to do with the Rectangle that you've created.
So to fix your problems, you need to do a few things.
Step 1: Create one instance of Rectangle for each rectangle you want to draw to the screen. In other words, you need to create an ArrayList that holds 9 Rectangle instances, not one.
Put this at the top of your sketch:
ArrayList<Rectangle> rectangles = new ArrayList<Rectangle>();
You never use your back variable, so you can get rid of it.
Put this inside your setup() function:
for (int row=0; row<back.length; row++) {
for (int coll=0; coll<back[row].length; coll++) {
float x = pad+(pad+bs)*coll;
float y = pad+(pad+bs)*row;
Rectangle rectangle = new Rectangle(x, y);
rectangles.add(rectangle);
}
}
This code loops through the coordinates and creates an instance of Rectangle at that position, and then adds it to the ArrayList. You'll also have to add the parameters to the Rectangle constructor.
Step 2: You can then shorten your draw() function to simply loop over the Rectangle instances in the ArrayList and draw them:
void draw() {
background(100);
for (Rectangle r : rectangles) {
r.show();
}
}
Step 3: Modify your show() function to include your logic for coloring the Rectangle based on the mouse position:
void show() {
if (mouseX >=x && mouseX<=x+size && mouseY>=y && mouseY<=y+size) {
//mouse is inside this Rectangle
rectt(x, y, size, size, color(255, 0, 0));
} else {
rectt(x, y, size, size, color(150));
}
}
See how each Rectangle knows how to draw itself based on its position and whether the mouse is inside it. All of our logic is inside this class instead of being split into two places.
Step 4: You can then add the dragging logic inside that if statement. If the cursor is inside the Rectangle and the mouse is being pressed, then you know the user is dragging that Rectangle:
//mouse is inside this Rectangle
if (mousePressed) {
x = mouseX - size/2;
y = mouseY - size/2;
}
Please note that I did this in regular Processing, not Processing.js, so you might have to make a few small adjustments like using mouseIsPressed instead of mousePressed. But the basic steps are the same: you need to move your logic inside your Rectangle class, and then you need to use the variables inside that class to draw each rectangle.
If you get stuck on a specific step then please post another question with your updated code and a description of exactly what you expect your code to do, what it does instead, and how those two things are different. Good luck.
You can find the answered in here: https://processing.org/examples/mousefunctions.html
But I will remember you that you can't use mouse event in the Object.
mouse-click-on-object