I'm trying to follow a tutorial on three.js, but coding it in React three fiber. Am stuck with the following snippet, to create a block, with line and edge geometries. Can anyone help, I basically need to convert it to R3F?
three.js:
function Block(x, y, z){
this.x = x;
this.y = y;
this.z = z;
this.display = function(){
var blockBox = new THREE.BoxBufferGeometry(5, 5, 5); // w, h, d
var blockMesh = new THREE.MeshBasicMaterial({color : 0x00ff00});
var block = new THREE.Mesh(blockBox, blockMesh);
scene.add(block);
block.position.x = this.x;
block.position.y = this.y - 10;
block.position.z = this.z;
var edges = new THREE.EdgesGeometry(blockBox);
var line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({color : 0x000000}));
scene.add(line);
line.position.x = this.x;
line.position.y = this.y - 10;
line.position.z = this.z;
}
}
What I have in React three fiber so far:
const Block = ({ x, y, z }) => {
return (
<mesh visible={true} position={[x, y, z]} scale={[1, 1, 1]}>
<boxGeometry />
<meshBasicMaterial wireframe color={"green"} />
<lineSegments >
<edgesGeometry />
</lineSegments>
</mesh>
);
}
Basically need help converting the snippet to R3F
Related
I am trying to make my canvas arcs (dog objects) follow the mouse cursor.
When I console.log the objects position or velocity it returns Vector{ x: NaN, y: NaN}
However, if I comment out the velocity assignment to the position, then the code seems to work as expected (without the object moving towards the mouse)
Why is this?
I'm not sure what to try to get this working?
// MAIN.JS
import Vector from './vector.js';
import Dog from './dog.js';
window.onload = function() {
let mouse = new Vector();
document.addEventListener('mousemove', (event)=> {
mouse.setXY(event.clientX, event.clientY);
});
const CANVAS = document.getElementById(`dogyard`),
CANVAS_CONTEXT = CANVAS.getContext(`2d`),
CANVAS_WIDTH = 800,
CANVAS_HEIGHT = 600;
CANVAS.width = CANVAS_WIDTH;
CANVAS.height = CANVAS_HEIGHT;
let dogs = [];
for(let i = 0; i < 1; i++){
dogs[i] = new Dog();
dogs[i].id = i;
dogs[i].color = `#A66253`;
dogs[i].position = new Vector(Math.floor(Math.random() * CANVAS_WIDTH), Math.floor(Math.random() * CANVAS_HEIGHT));
dogs[i].velocity = new Vector(0, 0);
dogs[i].acceleration = new Vector(0, 0);
}
function frames(){
// Clear the canvas/frame
CANVAS_CONTEXT.clearRect(0,0,CANVAS.width,CANVAS.height);
dogs.forEach( (dog, index, array) => {
// Draw the dog
CANVAS_CONTEXT.beginPath();
CANVAS_CONTEXT.fillStyle = dog.color;
CANVAS_CONTEXT.arc(dog.position.x,dog.position.y, 10,0, Math.PI*2);
CANVAS_CONTEXT.fill();
CANVAS_CONTEXT.closePath();
//Add the dog number
CANVAS_CONTEXT.font = "12px Arial";
CANVAS_CONTEXT.fillStyle = `#081E29`;
CANVAS_CONTEXT.fillText(index, dog.position.x , dog.position.y);
// Set Velocity to the current mouse position
dog.velocity.setVector(mouse);
//Subtract the mouse position from the dogs current position to determine distance
dog.velocity.sub(dog.position);
// Decrease the velocity by 20%
dog.velocity.mult(0.2);
// add the velocity to the dogs position
dog.position.add(dog.velocity);
})
requestAnimationFrame(frames);
}
frames();
}
// VECTOR.JS
export default class Vector{
constructor(x, y){
this.x = x;
this.y = y;
}
setXY(x,y){
this.x = x;
this.y = y;
}
setVector(vector){
this.x = vector.x;
this.y = vector.y;
}
add(vector){
this.x += vector.x;
this.y += vector.y;
}
sub(vector){
this.x -= vector.x;
this.y -= vector.y;
}
mult(number){
this.x *= number;
this.y *= number;
}
}
// DOG.JS
export default class Dog {
constructor(){
this.id;
this.position;
this.velocity;
this.acceleration;
this.color;
}
}
Console.log returns NaN
You do not initialize the coordinates of your mouse vector, so they are undefined. Replace it with var mouse = new Vector(0, 0);. Arithmetic operations on undefined happen to result in NaNs.
I am having problems with p5 js.
I am trying to add two ellipse objects that spin around the circumference of a circle.
The code below represents the constructor function of the object :
function Obj(){
this.ang = TWO_PI;
this.x = w/2 + cos(ang)*r;
this.y = h/2 + sin(ang)*r;
this.fil = 255;
this.size = 28;
this.show = function(){
noStroke();
fill(this.fil);
ellipse(this.x,this.y,this.size,this.size);
}
this.update = function(){
this.ang+=.02;
}
}
And this is the main file :
let w = innerWidth;
let h = innerHeight;
let xd = [];
let r = 200;
function setup() {
createCanvas(w, h);
for (let i = 0; i < 2; i++)
xd[i] = new Obj();
}
function draw(){
background(0,70,80);
noFill();
strokeWeight(7);
stroke(255);
ellipse(w/2, h/2, r*2, r*2);
xd[0].update();
xd[0].show();
}
The problem is that it says that ang is not defined even though i did clearly define it with this.ang = TWO_PI;. And if I declare it in the main file and in setup() I say ang = TWO_PI; the object stays in place. Can anyone help ?
Thank you.
The problem in the constructor function in this code, it should be like this :
this.x = w/2 + cos(this.ang)*r;
this.y = h/2 + sin(this.ang)*r;
Because you are using a property from the constructor function itself
I am a beginner to programming and I want to make a blackhole simulations, I can't draw objects using vectors as coordinates (and I want it to be this way so I can animate them afterwards using vectors), here is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>test trou noir</title>
<script>
var canvas, ctx;
var blackhole;
var circle;
var circles = new Array();
function init (){
var G = 6.67e-11, //gravitational constant
c = 3e8, //speed of light (m/s)
M = 12e31, // masseof the blackhole in kg (60 solar masses)
Rs = (2 * G * M) / 9e16, //Schwarzchild radius
pixel_Rs = Rs / 1e3,// scaled radius
canvas = document.getElementById ("space");
ctx = canvas.getContext ('2d');
drawCircle();
blackhole = new Ball (pixel_Rs, new Vector (700, 400), "black" );
blackhole.draw (ctx);
};
function Ball (radius, pos2D, color, vx, vy){
this.radius = radius;
this.pos2D = pos2D;
this.color = color;
this.vx = vx;
this.vy = vy;
};
Ball.prototype.draw = function (ctx){
ctx.fillStyle = this.color;
ctx.beginPath ();
ctx.arc ( pos2D, this.radius, 0, 2*Math.PI);
ctx.closePath ();
ctx.fill();
};
function drawCircle (ctx){
canvas = document.getElementById ("space");
ctx = canvas.getContext ('2d');
for (var i = 0; i<200; i++){
circle = new Ball (5,new Vector( Math.floor (Math.random()*1400), Math.floor (Math.random()*800)), "grey");
circle.draw (ctx)
circles.push (circle);
}
};
function Vector2D (x,y){
this.x = x;
this.y= y;
}
Vector2D.prototype = {
length: function (){
return this.x*this.x + this.y*this.y;
},
add: function (vec){
return new Vector2D (this.x + vec.x, this.y + vec.y);
},
subtract: function (vec){
return new Vector2D (this.x - vec.x, this.y - vec.y);
},
decrementBy: function (vec){
this.x -= vec.x;
this.y -= vec.y;
}
};
window.onload = init;
</script>
<style>
body {
background-color:#021c36 ;
margin: 0px;}
</style>
</head>
<body>
<canvas id ="space", width = "1400", height = "800">
</canvas>
</body>
</html>
Now, I think it is because the arc () method doesn't have specific coordinates, but then how can I implement vector coordinates so it draws something on the canvas? If someone have an idea it'd be great, also, if someone had a few tips as to how to animate 100 objects using vectors, it'd be great. Thanks alot
after your update I created the function update, but i can't make it work, here is the code:
function update (){
for (var i = 0; i<200; i++){
var vec2D = new Vector2D (Math.floor (Math.random()*1400), Math.floor (Math.random()*800));
circle = new Ball (5,vec2D.x,vec2D.y, "grey");
circle.draw (ctx)
circles.push (circle);
var distance = Math.sqrt (((vec2D.x-700)*(vec2D.x-700))+((vec2D.y400)* (vec2D.y-400)));
if (distance > pixel_Rs){
var delta = new Vector2D(1,1);
var forceDirection = Math.atan2(vec2D.y-700,vec2D.x-400);
delta.x += Math.cos(forceDirection)*3 ;
delta.y += Math.sin(forceDirection)*3;
vec2D.x += delta.x;
vec2D.y += delta.y;
requestAnimationFrame (update);
}
}
};
I did it without the force for now, but i can't make it work, do you know why?
PS:sorry about the code, my editing doesn't want to work properly :(
To draw with a vector.
// defining
var Vec = function(x,y){
this.x = x;
this.y = y;
}
// creating
var vec2D = new Vec(100,100);
// Using
ctx.arc(vec2D.x, vec2D.y, radius, 0, Math.PI *2);
To animate the vector you need to update it many times a second. Modern browsers provide a function to help you with that.
requestAnimationFrame(yourRenderFuntion) will call yourRenderFunction when it is ready for another frame. To use you create an update function that does all the drawing, and when done requests the next frame.
function update(time){ // Time is passed by requestAnimationFrame
// code to do the drawing and animation.
// request another frame
requestAnimationFrame(update);
}
// to start it
requestAnimationFrame(update);
Then you need to do the movements. I will create a second vector to hold the delta change per frame.
var delta = new Vec(1,1);
Then in the update function add the forces to the delta and add that to the position vector
// get direction of force
var forceDirection = Math.atan2(vec2D.y-blackHole.pos.y,vec2D.x-blackHole.pos.x);
// get magnitude of force
var force = getForce(vec2D); // get force of gravity you write that function
// apply that to the delta
delta.x += Math.cos(forceDirection) * force;
delta.y += Math.sin(forceDirection) * force;
// then update the position
vec2D.x += delta.x; // do it for both x and y axis
vec2D.y += delta.y;
Then you can draw the object at the next position.
I'm incredibly new to javascript and the way classes and methods work are confusing me.
Basically I have code like this:
function container(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
this.sumUp = function addUp(x, y, z) {
var a = x + y + z;
};
}
What I want to do is elsewhere in my code use the function defined within the container, using the values in container. How do I actually go about doing this?
Something along the lines of
container1 = new container (1, 2, 3);
container.sumUp(this.x, this.y, this.z);
Or something like that. I'm very confused and thinking I'm going about the whole thing wrong.
I think you want somwthing like this:
function Container(x, y, z){
this.x = x;
this.y = y;
this.z = z;
this.sumUp = function addUp(x, y, z){
alert(this.x + this.y + this.z);
};
}
container_instance = new Container(1, 2, 3);
container_instance.sumUp();
But I recomend:
function Container(x, y, z){
this.x = x;
this.y = y;
this.z = z;
}
Container.prototype.sumUp = function addUp(x, y, z){
alert(this.x + this.y + this.z);
};
container_instance = new Container(1, 2, 3);
container_instance.sumUp();
That is how it works (short):
In JavaScript you have objects, they are like hashes:
var obj = {
'a': 1,
'b': 2,
'c': 3
};
And you can get or set values by keys:
alert(obj.a); // alerts 1
alert(obj['a']); // same thing
obj['c'] = 4;
In your case Container is function which will build your object. When you do new Container(1, 2, 3); it creates an empty object, and execute the function in the context of the object.
function Container(x, y, z){
this.x = x;
this.y = y;
this.z = z;
}
// There is no point to put parameters there since they are already instance variables.
Container.prototype.sumUp = function addUp(){
alert(this.x + this.y + this.z);
};
container_instance = new Container();
container_instance.sumUp();
I would like to create a custom Raphael element, with custom properties and functions. This object must also contain predefined Raphael objects. For example, I would have a node class, that would contain a circle with text and some other elements inside it. The problem is to add this new object to a set. These demands are needed because non-Raphael objects cannot be added to sets. As a result, custom objects that can contain Raphael objects cannot be used. The code would look like this:
var Node = function (paper) {
// Coordinates & Dimensions
this.x = 0,
this.y = 0,
this.radius = 0,
this.draw = function () {
this.entireSet = paper.set();
var circle = paper.circle(this.x, this.y, this.radius);
this.circleObj = circle;
this.entireSet.push(circle);
var text = paper.text(this.x, this.y, this.text);
this.entireSet.push(text);
}
// other functions
}
var NodeList = function(paper){
this.nodes = paper.set(),
this.populateList = function(){
// in order to add a node to the set
// the object must be of type Raphael object
// otherwise the set will have no elements
this.nodes.push(// new node)
}
this.nextNode = function(){
// ...
}
this.previousNode = function(){
// ...
}
}
You can only add Raphael object (rect,circle, eclipse,text) to paper.set(), not self defined object( with Raphael.fn) . Instead use normal array definition of javascript [].
As fas as i understand nodeList is a simple list but with more options like nextnode , previous nodes.
Take a look at this demo, i changed abit José Manuel Cabrera's codes: http://jsfiddle.net/Tomen/JNPYN/1/
Raphael.fn.node = function(x, y, radius, txt) {
this.x = x;
this.y = y;
this.radius = radius;
this.txt = txt;
this.circleObj = paper.circle(this.x, this.y, radius), this.textObj = paper.text(this.x, this.y, this.txt);
this.entireSet = paper.set(this.circleObj, this.textObj);
return this
}
Raphael.fn.nodeList = function() {
this.nodes = [];
this.push = function(p) {
return this.nodes.push(p);
};
// this.nextNode = function(){
// ... manipulate this.nodes here
// }
// this.previousNode = function(){
// ...
// }
return this
}
var ca = paper.node(250, 150, 50.0, "hola");
var list = paper.nodeList();
list.push(ca);
Some examples may fall down if there is no global 'paper'
The context of Raphael.fn.yrMethod will be the instance (paper)
This example creates a raphael object which wraps a g element, which is for some reason not currently supported:
(function(R){
function g(_paper){
var _canvas = _paper.canvas,
_node = document.createElementNS("http://www.w3.org/2000/svg", "g");
_canvas.appendChild(_node);
this.add = function(rElement){
_node.appendChild(rElement.node);
}
this.remove = function(rElement){
_canvas.appendChild(rElement.node);
}
this.transform = function(tString){
_node.setAttribute('transform', tString);
}
}
R.fn.g = function(){
return new g(this);
}
})(Raphael);
this code allow you to create a node with a text (it returns a set) and you can manipulate it as a Raphael object (put the method after loading the dom):
function loadShape(){
Raphael.fn.node = function(x, y, radius, txt){
this.x = x;
this.y = y;
this.radius = radius;
this.txt = txt;
this.drawCircle = function () {
return paper.circle(this.x, this.y, radius);
};
this.drawText = function () {
return paper.text(this.x, this.y, this.txt);
};
this.draw = function(){
var group = paper.set();
var circulo = paper.circle(this.x, this.y, radius);
var texto = paper.text(this.x, this.y, this.txt);
group.push(circulo);
group.push(texto);
return group;
}
this.init = function(ox, oy, r, t){
this.x = ox;
this.y = oy;
this.radius = r;
this.txt = t;
};
// etc…
return this;
};
var paper = new Raphael(document.getElementById("wrapper"), "100%", "100%");
//var nodo = paper.node();
//nodo.init(50, 50, 2.0, "soy un nodo");
var nodo = paper.node(250, 150, 50.0, "hola");
nodo.draw();
//circ.attr({"propiedad":"hola"});
//alert(circ.attr("propiedad"));
}
Tell me if this was useful to you!