Javascript Classes Sharing Functions? - javascript

Let's say I have two classes, one called Rectangle and one called Circle. Both classes have the values X and Y, is there a way to define the variables and functions once for both of the classes? Read the code below if it explains it better:
function Rectangle(msg, font){
this.msg = msg;
this.font = font;
}
function Circle(radius){
this.radius = radius;
}
Rectangle && Circle {
/* had no idea how to write the line above,
but basically for both the rectangle and the circle,
there is this code so I don't have to rewrite it for both.*/
this.position = function(x, y){
this.x = x;
this.y = y;
}
}

Yes, there is:
//creating class shape
function Shape(x,y){
this.x = x;
this.y = y;
};
//set position function
Shape.prototype.position = function(x,y){
this.x = x;
this.y = y;
};
function Rectangle(msg,font,x,y){
//calling object Shape
Shape.call(this,x,y);
this.msg = msg;
this.font = font;
}
//inheriting object Shape
Rectangle.prototype=Object.create(Shape.prototype);
function Circle(radius,x,y){
//calling object Shape
Shape.call(this,x,y);
this.radius = radius;
}
//inheriting object Shape
Circle.prototype=Object.create(Shape.prototype);
You can now call any function defined in Shape from a Rectangle or Circle object. Hope this helps.

Related

Adding Velocity to Objects Position Returns NaN

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.

Constructor not working properly in p5 js

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

best design practice to separate common code?

I have a card class:
function Card() {
this.image = new Image();
this.x = 0;
this.y = 400;
this.initialX = 0;
this.initialY = 0;
this.scaleFactor = 4;
this.setImage = function(ii){
this.image.src = ii;
};
this.getWidth = function(){
if (this.image == null){
return 0;
}
return this.image.width / this.scaleFactor;
}
this.getHeight = function(){
if (this.image == null){
return 0;
}
return this.image.height / this.scaleFactor;
}
this.pointIsInCard = function(mx, my){
if (mx >= this.x && mx <= (this.x + this.getWidth()) && my >= this.y && my <= (this.y + this.getHeight()))
{
return true;
}
else{
return false;
}
};
};
I then have a deck class:
function Deck(x, y, w, h){
this.x = x;
this.y = y;
this.width = w;
this.height = h;
this.cards = [];
}
I need to add a method in Deck class similar to pointIsInCard instead it will be called pointIsInDeck. The logic will be same i.e to check whether the passed in point falls in the boundary of the object. So seeing this duplication of code I wanted to know what is a good design practice to avoid this duplication? One option I thought of was to extract the method out and create a function for generic object with x, y, width, height but again from OOP principles I thought this method should belong to the class/object. I appreciate any help! Thanks!
A common approach for what you're doing is to attach a Rectangle or similar instance with that functionality to both of your objects, that is:
class Rectangle {
constructor(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
containsPoint(x, y) {
return x >= this.x && x =< this.width &&
y >= this.y && y =< this.height;
}
}
Then just add it to Card and Deck:
function Card() {
this.rect = new Rectangle(/* Your card shape */);
// ...
}
function Deck() {
this.rect = new Rectangle(/* Your deck shape */);
// ...
}
And you can do:
card.rect.containsPoint();
deck.rect.containsPoint();
If these are classes related to drawing, they would both inherit from something like Rectangle, which they would both inherit this behaviour from.
If they are gameplay-related, I would prefer them each referencing a Rectangle (or its subclass) that they would delegate all UI-related tasks to; then reduce this to the previous paragraph's solution.
You can use Function.prototype.call() to set this at a function call
function Card() {
this.x = 1; this.y = 2;
};
function Deck() {
this.x = 10; this.y = 20;
}
function points(x, y) {
// do stuff
console.log(x, this.x, y, this.y); // `this`: `c` or `d`
}
var c = new Card();
var d = new Deck();
points.call(c, 3, 4); // `this`: `c` within `points` call
points.call(d, 100, 200); // `this`: `d` within `points` call

Undefined variable immediately after declaring it?

I'm creating a Game Loop in javascript using var/function classes (for want of a better word). However, I have this strange error where javascript states that a variable is undefined immediately after declaring it...
main.js:39 Uncaught ReferenceError: game is not defined
In this case, that line is;
game.context.beginPath();
However, this line is not called until the init function calls game.balls.push(/../); Haven't I already declared 'game' by this point, or am I missing something?
Here is my code (Apologies for the length, hopefully most of it can be ignored):
/*
Keep This: #217398
*/
var Game = function () {
this.canvas = document.getElementById('canvas');
this.context = this.canvas.getContext('2d');
this.balls = [];
var that = this;
this.start = function () {
requestAnimationFrame(that.update);
};
this.update = function () {
that.draw();
requestAnimationFrame(that.update);
};
this.draw = function () {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
for(var x = 0; x < this.balls.length; x++){
this.balls[x].draw();
}
};
this.start();
};
var Ball = function (x, y) {
this.x = x;
this.y = y;
this.dx = 2;
this.dy = 2;
this.ballRadius = 10;
this.draw = function(){
game.context.beginPath();
game.context.arc(this.x, this.y, this.ballRadius, 0, Math.PI*2);
game.context.fillStyle = 'black';
game.context.fill();
game.context.closePath();
this.x += this.dx;
this.y += this.dy;
if(this.x + this.dx > game.canvas.width - this.ballRadius || this.x + this.dx < this.ballRadius)
this.dx = -this.dx;
if(this.y + this.dy > game.canvas.height - this.ballRadius || this.y + this.dy < this.ballRadius)
this.dy = -this.dy;
};
};
function init(){
var game = new Game();
game.canvas.addEventListener('click', function(){
game.balls.push(new Ball(100, 100));
});
}
Update Ball() so that you can explicitly pass in a reference to the Game() instance:
var Ball = function (game, x, y) {
this.x = x;
this.y = y;
// etc
};
Then:
function init(){
var game = new Game();
game.canvas.addEventListener('click', function(){
game.balls.push(new Ball(game, 100, 100));
});
}
Now the Ball() code has access to a reference to the Game() instance you created.
Because you declared the game variable using the var keyword within the init function, it will be scoped to the init function (and not available to other functions not nested within init).
function init(){
var game = new Game(); // will be scoped to init
game.canvas.addEventListener('click', function(){
game.balls.push(new Ball(100, 100));
});
}
So, one option would be to declare game outside of init which would broaden it's scope, or you could declare it as an instance variable to Ball.
The variable game is scoped to the init function in which it is created. This means that it can't be accessed outside of this function. There are many work arounds for this. You could make game a global variable, or pass it to the Ball constructor.
Another possible solution is having a global namespace which keeps track of these important objects.
var SomeNamespace= {};
SomeNamespace.game= new Game();
What I personally like to do is run my simple games in closures.
(function(){
var game = new Game();
var ball = new Ball(); // Ball now has access to game.
})()
Sidenote, you can create globally scoped variables within functions, by omitting the var keyword, but it's considered a bad practice.

Javascript calling a class method using variables in the class

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();

Categories