I'm trying to create a very basic physics simulation in p5.js and I am using a class to create multiple instances of the shapes (which are currently all circles), I have a function that checks if the user clicks inside the area of a circle and if so allows them to drag it around but I ran into a problem. I need to have the program work out which object it is hovering but I'm not sure how I would do so, below I have the function working for only the first object (obj1). can I do something like {classname}.posX instead?
function whilePressed()
{
if (Math.pow(mouseX-obj1.posX,2)+(Math.pow(mouseY-obj1.posY,2))<=(Math.pow(obj1.size/2,2)) | grabbed == true)
{
grabbed = true;
if (firstGrab == true)
{
difX = (obj1.posX-mouseX);
difY = (obj1.posY-mouseY);
firstGrab = false;
}
obj1.posX = mouseX+difX;
obj1.posY = mouseY+difY;
}
}
below is the class (the draw function has a switch statement in it because I used to have a square as well but decided to get a circle working before implementing a square)
class primitive
{
constructor()
{
this.size = 50;
this.posX = canvasSize/2;
this.posY = canvasSize/2;
this.velX = 0;
this.velY = 0;
this.terminalVel = 15;
}
pos(x,y)
{
this.posX = x;
this.posY = y;
}
draw(shape = 'circle')
{
stroke(168,198,159);
fill(204,226,163);
switch (shape)
{
case 'circle':
circle(this.posX,this.posY,this.size);
break;
}
}
gravity()
{
if (this.velY < this.terminalVel)
{
this.velY = (this.velY+1);
}
else
{
this.velY = 20;
}
this.posY = this.posY+this.velY;
if (this.posY > groundLevel-(this.size/2))
{
this.posY = groundLevel-(this.size/2);
this.velY = 0;
}
}
}
You can create a static method on the primitive class like so:
First, create an array which has all the instances of the class in it.
This is the code:
Remember: I added the parameter name to the constructor. That means when creating an instance do it like so:
var foo = new primitive("foo");
var PRIMITIVES = [];
// ...
constructor(name)
{
this.name = name;
this.size = 50;
this.posX = canvasSize/2;
this.posY = canvasSize/2;
this.velX = 0;
this.velY = 0;
this.terminalVel = 15;
PRIMITIVES.push(name);
}
Now, using the same mouse find principle, you can create a static method that finds and return the right instance.
static findInstance(mouseX, mouseY) {
for (var i = 0; i < PRIMITIVES.length; i++)
{
obj = window[PRIMITIVES[i]];
if (Math.pow(mouseX-obj.posX,2)+(Math.pow(mouseY-obj.posY,2))<=(Math.pow(obj.size/2,2)))
{
return obj;
}
}
}
Then, you can call primitive.findInstance(mouseX, mouseY), and it will return the right instance. If this doesn't work, please comment. I hope this helped you.
Create an array of objects:
let objects = []
objects.push(obj1);
objects.push(obj2);
Implement an algorithm in the mousePressed() callback that detects the clicked object:
let draggedObject;
let dragOffsetX;
let dragOffsetY;
function mousePressed() {
draggedObject = null;
for (let i=0; i < objects.lenght; i++) {
obj = objects[i];
if (Math.pow(mouseX-obj.posX,2) + Math.pow(mouseY-obj.posY,2) <= Math.pow(obj.size/2,2)) {
draggedObject = obj;
dragOffsetX = draggedObject.posX - mouseX;
dragOffsetY = draggedObject.posY - mouseY;
break;
}
}
}
Change the position of the object in the mouseDragged() callback:
function mouseDragged() {
if (dragged_object) {
draggedObject.posX = mouseX + dragOffsetX;
draggedObject.posY = mouseY + dragOffsetY;
}
}
Related
I'm developing a little game of nothing at all more commonly called "Pathfinding"; and I am crashing on a small error that I have never encountered (I am young dev);
I have searched everywhere but I do not understand why this error appears.
I am experiencing this error:
Uncaught TypeError: current.distance is not a function
at search_min_distance (pathfinding.js:127)
at game (pathfinding.js:151)
at HTMLDocument. (pathfinding.js:173)
document.addEventListener("DOMContentLoaded", function() {
const NBR_POINT = 10;
const MIN_SPACING = 100;
const HEIGHT = window.innerHeight;
const WIDTH = window.innerWidth;
class point {
constructor(x, y, name, id) {
this.x = x;
this.y = y;
this.part = document.createElement("div");
this.part.className = name;
this.part.id = id;
}
distance(cmp) {
return Math.sqrt(Math.pow(cmp.x - this.x, 2) + Math.pow(cmp.y - this.y, 2));
}
}
function random(mode) {
if (!mode)
return Math.random() * ((WIDTH - 100) - 100) + 100;
else
return Math.random() * ((HEIGHT - 100) - 100) + 100;
}
function printPoint(stk, crt) {
var block = 0;
do {
block = 0;
var x = random(0);
var y = random(1);
if (stk.length != 0) {
for (let i = 0; i < stk.length; i++) {
if (x < (stk[i].x + MIN_SPACING) && x > (stk[i].x - MIN_SPACING) && y < (stk[i].y + MIN_SPACING) && y > (stk[i].y - MIN_SPACING)) {
block = 1;
break;
}
}
}
} while (block == 1);
var ids = stk.length + 1;
if (crt == "current")
var p = new point(x, y, "point courant", ids);
else
var p = new point(x, y, "point", ids);
p.part.style.bottom = p.y + "px";
p.part.style.left = p.x + "px";
document.body.appendChild(p.part);
return p;
}
function polyPoint() {
var stk = new Array();
for (let i = 0; i < NBR_POINT - 1; i++) {
stk.push(printPoint(stk, null));
}
printPoint(stk, "current");
return stk;
}
function imp_session() {
var dark_status = sessionStorage.getItem('dark_mode');
if (dark_status == 1)
document.body.classList.add("darkmode");
if (dark_status == 0)
document.body.classList.remove("darkmode");
}
function srv_DarkMode() {
document.addEventListener("keypress", function(event) {
let keypress = event.key;
var dark_status = sessionStorage.getItem('dark_mode');
if (keypress == "d") {
if (dark_status == null) {
dark_status = 0;
sessionStorage.setItem('dark_mode', dark_status);
}
if (dark_status == 1) {
this.body.classList.remove("darkmode");
dark_status = 0;
//To be able to delete sessions and not add them afterwards and error duplicate key.
sessionStorage.removeItem('dark_mode');
sessionStorage.setItem('dark_mode', dark_status);
} else {
this.body.classList.add("darkmode");
dark_status = 1;
//To be able to delete sessions and not add them afterwards and error duplicate key.
sessionStorage.removeItem('dark_mode');
sessionStorage.setItem('dark_mode', dark_status);
}
}
});
}
function search_min_distance(stk, current) {
let min = current.distance(stk[0]);
let tmp;
let real = min;
for (let i = 1; i < stk.length; i++) {
if (stk[i].id = current.id)
continue;
tmp = current.distance(stk[i]);
if (tmp < min)
real = i;
}
return real;
}
function game(stk) {
var cp = document.getElementsByClassName('courant');
cp[0].addEventListener("click", function(event) {
alert("txt");
});
var distId = search_min_distance(stk, cp[0]);
var p = document.getElementsByClassName('point');
for (let i = 0; i < p.length; i++) {
if (p[i].id != cp[0].id || p[i].id != distId) {
p[i].addEventListener("click", function(event) {
alert("txt");
});
}
}
}
function init() {
imp_session();
srv_DarkMode();
return polyPoint();
}
game(init());
});
-> current and stk [0] are indeed of "type" point.
All the remaining code does not seem important to me, but if necessary I will provide it.
I thank you in advance ! Be indulgent...
The point you are getting using the getElement function just returns
the js object, it does not contain any functions from the class.
You need to create a new class instance from this obtained point as follows inside the search_min_distance function
const { x, y, name, id } = current;
const currentPoint = new Point(x, y, name, id);
let min = currentPoint.distance(stk[0]);
I suggest you write a util function to calculate the distance between two points, passing the two points as arguments. It will be a cleaner approach.
Bind distance function to this inside constructor
class point {
constructor(x, y, name, id) {
this.x = x;
this.y = y;
this.part = document.createElement("div");
this.part.className = name;
this.part.id = id;
// bind distance method
this.distance = this.distance.bind(this);
}
distance(cmp) {
return Math.sqrt(Math.pow(cmp.x - this.x, 2) + Math.pow(cmp.y - this.y, 2));
}
}
The name of error is "TypeError". And That's not just for fun. Possible problems in search_min_distance:
stk is not defined or its length is 0
stk is not array of points (typeof point[])
point is not defined or it's not point (typeof point)
Sure problems:
point.id is not defined, it's only in point.part
if (stk[i].id = current.id)
to
if (stk[i].part.id = current.part.id)
Your code is only errors.
Finally all this for a simple mistake of inattention; I took dom for my array and put an assignment where there should have been an equal .. thanks everyone.
if (stk[i].id = current.id)
as
if (stk[i].id == current.id)
and
var distId = search_min_distance(stk, cp[0]);
as
var distId = search_min_distance(stk, stk[cp[0].id]);
I have the class Map with a property this.guns = [ ]. I deleted some parts of the code to make it easy to read.
class Maps {
constructor(canvas, sizeX, sizeY, sizeCase) {
this.guns = [];
}
} // end class
Inside this.weapon = [ ] I pushed some objects with its properties. Those objects were instantiated in the Map class.
/* eslint-disable no-console */
class Maps {
constructor(canvas, sizeX, sizeY, sizeCase) {
this.guns = [];
}
setGuns(quantity) {
// this.guns = [];
for (let index = 0; index < quantity; index++) {
const x = App.random(this.size.x);
const y = App.random(this.size.y);
let element;
if (this.mapGame[y][x] === 0) {
switch (index) {
case 0: {
element = new Gun(4, "watermelon", 15, y, x);
this.mapGame[element.y][element.x] = 2;
console.log(element);
this.guns.push(element);
break;
}
case 1: {
element = new Gun(5, "eggplant", 20, y, x);
this.mapGame[element.y][element.x] = 3;
console.log(element);
this.guns.push(element);
break;
}
default:
break;
}
} else {
index -= 1;
}
}
console.log(this.guns);
}
} // end class
I have an other class call Player with a method to move the players. When the player is over a weapon, take the weapon. To do this, I have done the checkWeapon method.
class Player {
constructor(imagePlayer, name, score, positionY, positionX) {
this.imagePlayer = imagePlayer;
this.name = name;
this.score = score;
this.x = positionX;
this.y = positionY;
this.movementAccumulator = 0;
this.limitMovement = 3;
this.weapon = {};
}
/**
* I deleted the not necessary methods, and then the rest of cases on the switch
*/
movement(direction, map, currentPlayer) {
const collision = this.rockCollision(direction, map);
switch (direction) {
case up:
if (this.y > 0) {
if (!collision) {
map.mapGame[this.y][this.x] = 0; // draw grass
this.y -= 1;
this.whoPlayerIsMoving(map, currentPlayer);
this.counterMovement();
this.checkWeapon(map);
}
}
break;
}
checkWeapon(map) {
this.weapon = map.getGun(this.y, this.x);
}
}
Player send throung the checkWeapon method the coordinates x and y, to an other method hosted on the class Map, the getGuns method.
/* eslint-disable no-console */
class Maps {
constructor(canvas, sizeX, sizeY, sizeCase) {
this.guns = [];
}
/**
* The console log are to render(or print) on the console and look if everything goes well.
* The following method is a test, is bad done and it have to be refatoriced
*/
getGun(y, x) {
console.log(`Re Y:${y}` + ` Re X: ${x}`);
console.log(`${this.guns[0].y} ${this.guns[0].x}`);
if (this.guns[0].y == y && this.guns[0].x == x) {
console.log("soy un arma");
}
return gunTaked;
}
} // end class
My main problem is, how to access to the properties of the Gun object. I did the method above, but I got stuck. I have reading about destructuring, but I am not sure if, should I apply it here. Thanks
I have this
class Maps {
constructor(canvas, sizeX, sizeY, sizeCase) {
this.canvas = document.getElementById("canvas");
this.canvas.width = sizeX * sizeCase;
this.canvas.height = sizeY * sizeCase;
this.size = { x: sizeX, y: sizeY, case: sizeCase };
this.ctx = this.canvas.getContext("2d");
this.tileMap = new Image();
this.tileMap.src = "img/tileMap.png";
this.mapGame = [];
this.FPS = 50;
this.weapons = [
{ idWeapon: 2, name: "watermelon", power: 15 },
{ idWeapon: 3, name: "eggplant", power: 20 },
{ idWeapon: 4, name: "pumkin", power: 25 },
{ idWeapon: 5, name: "broccoli", power: 30 }
];
}
}
The object array isn´t inside the code, I pasted like and example to add more information
Don´t worry by the sintaxis, I am breaking my class in small pieces to don´t paste all the code.
What I want to do, is: 1. find de the objecto I need, It is alredy done, checking the idWeapon
My main problem it is, how to extract the object and hosted in a variable and later if I find an other weapon, let the current weapon and take the new one
I'm trying to create a board game and would like to instantiate the class Human based on a number of times provided by the user. Obviously I'm trying to assign a different ID per object and the following loop doesn't work in order to instantiate the number of players:
var question = prompt('how many players');
var numOfPlayers = parseInt(question);
class Human {
constructor (id) {
this.id = id;
this.health = 100;
this.hammer = false
this.knife = false;
this.sword = false;
this.baseballbat = false;
this.damage = 0;
this.location = {
x: Math.floor(Math.random() * 8),
y: Math.floor(Math.random() * 8)
}
}
moveTo(x, y){
this.location.x += x;
this.location.y += y;
}
}
var i;
for (i = 0; i < numOfPlayers; i++) {
const player = new Human(id = i);
}
Firstly, I hope I have understood what you are trying to achieve here. The scope of the "const player" is limited within the loop. If you want to be able to access it outside the loop you need to declare a list/array likewise.
Code may go like this for the same:
var players = [];
for(let i = 0; i < numOfPlayers; i++) {
players.push(new Human(i));
}
Note: If you don't want to use variable 'i' outside the loop you can declare it inside 'for' using 'let' keyword as can be seen in the code above.
class Human {
constructor (id){
this.id = id;
this.health = 100;
this.hammer = false
this.knife = false;
this.sword = false;
this.baseballbat = false;
this.damage = 0;
this.location = {
x:Math.floor(Math.random()*8),
y:Math.floor(Math.random()*8)
}
console.log(`Human created with id of ${id}`); //Remove this just to show you that your class is being instantiated for each 'player'
}
moveTo(x,y){
this.location.x += x;
this.location.y += y;
}
}
let numOfPlayers = prompt('How many players?');
const _init = () => {
if(parseInt(numOfPlayers) > 0) {
for (let i = 0; i < numOfPlayers; i++) {
new Human(i)
}
}
}
_init();
I have multiple objects like this(16)
function Baboo(x,y,size,speed,target,sps,life){
MobRoot.call(this,x,y,size,speed,target,sps,life);
this.spsCoord = [500*0,500*3,500,500];
this.coolDown = 60;
this.atack = 0;}
Baboo.prototype = Object.create(MobRoot.prototype);
Baboo.prototype.throw = function()
{
projectiles.push(new Arrow(this.x,this.y,10,10,this.angle,150,this.target));
}
Baboo.prototype.update = function(){
if(this.life>0)
{
this.sendBack();
this.draw();
this.checkClick();
this.angle = CalculateSlope(this,this.target);
this.directionUpdate();
this.updateBuffs();
this.x += this.direction.x;
this.y += this.direction.y;
}}
/*etc aditional methods*/
that inherit all from this object
function MobRoot(x,y,size,speed,target,sps,life)
{
this.size = size*WindowScale;
this.x = x;
this.y = y;
this.angle = 0;
this.speed=speed;
this.colided=false;
this.maxlife = life;
this.life = life;
this.buffArray = [];
this.sps = sps;
this.target = target;
this.direction =
{
x:0,
y:0
}
//x,y,w,h
//ex sprite[0][0] = 0,0,500,500;
this.spsCoord = [];
this.isBoss = false;
}
MobRoot.prototype.directionUpdate = function()
{
this.direction.x = this.speed*Math.cos(this.angle)*-1;
this.direction.y = this.speed*Math.sin(this.angle)*-1;
}
/*aditional methods for mobRoot*/
and I want to generate different mobs from an array. At the moment I'm assigning a number for each type (ex: 1-Baboo 2-Spider 3-Whatever) and storing these numbers in arrays, and when I'm generating them i use a switch for each mobIndex from the array like this
switch(wave[i])
{
case 1:
mobs.push(new Baboo(arg1,arg2,...));
break;
case 2:
mobs.push(new Spider(arg1,arg2,...));
break;
/*...*/
case 999:
mobs.push(new Whatever(arg1,arg2,...));
break;
}
Is there a more elegant way of solving this kind of problem?
You can put all the constructors into an array:
var constructors = [Baboo, Spider, Whatever, ...];
if (wave[i] < constructors.length) {
mobs.push(new constructors[wave[i]](arg1, arg2, arg3, ...));
}
I would like to start organizing my code properly, so I want to use object literals. In the following case, I'm doing a pseudo class. I would like that init() could work as a constructor, but unfortunately, I'm not seeing how to set attributes based on object context.
var car = {
context : this,
wheels : 0,
color : '',
speed : 0,
init : (function(x){
console.log(x);
x.wheels = 4;
x.color = 'red';
x.speed = 120;
})(context)
};
console.log(car.color);
You can't immediately run a function like that whilst declaring an object literal. What you can do:
var car = {
init : function(wheels,color,speed){
this.wheels = wheels || 0;
this.color = color || '';
this.speed = speed || 0;
return this;
}
}.init(4,'red',120);
alert(car.speed); //=>120
Which removes the need for:
context : this,
wheels : 0,
color : '',
speed : 0,
...and offers the possibility for:
var car = {
init : function(wheels,color,speed){
this.wheels = wheels || 0;
this.color = color || '';
this.speed = speed || 0;
return this;
}
},
redAndFast = car.init(4,'red',230),
threeWheeler = car.init(3,'yellowstriped',110);
[edit] What was I thinking? If you want more instances of Car, you'll have to use a real constructor function instead of an object literal:
var Car = function(){
return {
init : function(wheels,color,speed){
this.wheels = wheels || 0;
this.color = color || '';
this.speed = speed || 0;
return this;
}
}
},
redAndFast = new Car().init(4,'red',230),
threeWheeler = new Car().init(3,'yellowstriped',110);
Which can be simplified to:
var Car = function(wheels,color,speed){
this.wheels = wheels || 0;
this.color = color || '';
this.speed = speed || 0;
},
redAndFast = new Car(4,'red',230),
threeWheeler = new Car(3,'yellowstriped',110);
Or if you wanted to cling on to some init like function:
var Car = (function(){
function car(wheels,color,speed){
this.wheels = wheels || 0;
this.color = color || '';
this.speed = speed || 0;
}
return {
init: function(w,c,s){
return new car(w,c,s);
}
};
})(),
redAndFast = Car.init(4,'red',230),
threeWheeler = Car.init(3,'yellowstriped',110);
But hey, what happened to my context? you may ask. Well, it turns out you didn't need it after all. Isn't javascript a beautiful and flexible language?
var Car = function() {
this.wheels = 4;
this.color = 'red';
this.speed = 120;
}
var car = new Car();
It's best to use normal constructors for these kind of tasks.
Object literals work for singletons. If you want an instantiable object, you'll need to learn how js oop works and just use function objects.