I'm making a simple game where you can add objects(cubes) at the raycaster(mouse) position when you click on a big plane(ground). I don't want that objects(cubes) can placed in each other. I made a simple collision detection. I know this isn't the best way to do this, but this is the way I understand what I'm doing.. I am a beginner.
In the following code I check the positions of both objects. With these positions I check the distance between it. If the distance is smaller than 4098(which is 64*64) it add the object to the scene.
function onDocumentMouseDown( event ) {
event.preventDefault();
mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( clickObjects );
var intersects2 = raycaster.intersectObjects( objects );
if ( intersects.length > 0 ) { // Clicking on the ground?
if ( intersects2.length > 0 ) { // Clicking on an object?
}else{
var geometry = new THREE.BoxGeometry( 64, 64, 64);
var cube = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0xFBF5D7, opacity: 1 } ) );
cube.position.copy(intersects[0].point);
cube.position.y = 30;
cube.flipSided = true;
cube.doubleSided = true;
var validposition = true;
var i;
for (i = 0; i < objects.length; i++) {
var dx = cube.position.x - objects[i].position.x;
var dy = cube.position.y - objects[i].position.y;
var dz = cube.position.z - objects[i].position.z;
var distance = dx*dx+dy*dy+dz*dz;
if(distance < 4096) {
validposition = false;
}
}
if(validposition == true) {
objects.push(cube);
scene.add(cube);
}
}
}
}
The problem is that this only works when it is a square object. Can anyone help me how I can think in which way for a rectangle object like THREE.BoxGeometry( 64, 64, 400)?
I wrrote some time ago a remake of the frogger game from C64. There I had to control that my frog has no contact to the cars.
var img1_x1 = parseInt(idImg.style.left);
var img1_x2 = img1_x1 + idImg.width - 1;
var img1_y1 = parseInt(idImg.style.top);
var img1_y2 = img1_y1 + idImg.height - 1;
img2_x1 = parseInt(idImg2.style.left);
img2_x2 = img2_x1 + idImg2.width - 1;
img2_y1 = parseInt(idImg2.style.top);
img2_y2 = img2_y1 + idImg2.height - 1;
if (((img2_x1 <= img1_x2 && img1_x2 <= img2_x2) || (img2_x1 <= img1_x1 && img1_x1 <= img2_x2) || (img1_x1 <= img2_x1 && img2_x1 <= img1_x2))
&& ((img2_y1 <= img1_y2 && img1_y2 <= img2_y2) || (img2_y1 <= img1_y1 && img1_y1 <= img2_y2) || (img1_y1 <= img2_y1 && img2_y1 <= img1_y2)))
{
alert('boom');
}
Look at my code perhaps there is something usefull for you. I first calculate the position of my frog (img1) and than use a for-loop over all my test-objects (here not displayed). In this loop I calculate the position for the object (img2) and afterwards I make the control of overlapping.
You had to add the third dimension to the conditions which I didn'tz needed.
Note: For img2 I don't use the var in my for-loop I declared it outside in the function.
I copied here only a few sections from my code and cut off confusing parts.
Related
I am making a 2d platformer and am working on gravity and collision but when I actually get the collision working my gravity became very stuttery, is there a way to fix this? here is code:
gravity(){
if(this.y <= 400 - this.scale){
let gc = get(this.x, this.y + 20);
print(gc);
if(gc[0] == 0 && gc[1] == 0 && gc[2] == 255 && gc[3] == 255){
return;
}
else{
this.y += 2;
}
}
}
edit: I have heard this should be working so I will provide more code to see if it helps. here is the function that runs everything:
var groundArray = [];
groundArray[0] = [0];
groundArray[1] = [0];
groundArray[2] = [0];
groundArray[3] = [0];
groundArray[4] = [0];
groundArray[5] = [0];
groundArray[6] = [0];
groundArray[7] = [0];
groundArray[8] = [1];
groundArray[9] = [1, 1];
function setup() {
noStroke();
createCanvas(400, 400);
for(let y = 0; y < groundArray.length; y++){
for(let x = 0; x < groundArray[y].length; x++){
if(groundArray[y][x] != 0){
groundArray[y][x] = new ground(x * 40, y * 40);
}
}
}
}
var play = new player(35, 0, 20);
function draw() {
background(255);
for(let y = 0; y < groundArray.length; y++){
for(let x = 0; x < groundArray[y].length; x++){
if(groundArray[y][x] != 0){
groundArray[y][x].draw();
}
}
}
play.draw();
play.gravity();
}
Normally a function named draw() is called every frame, is that what's happening here? It looks like it. In which case, do you really want to be calling new ground(x * 40, y * 40) every frame, wouldn't this object creation be better placed in setup()?
I suspect it's unnecessary and possibly doing expensive initialization work every frame, but without seeing the full source code one can't be sure.
I have a object that has many child objects and I only want the children to change a specific value, not affecting the parent object. In short, the children have values that WILL change but the children are changing the parent as well, which is bad.
Only Relevant JS:
let p1 = {super:{vel:{x:3,y:0}, timeLeft:100}} // Very Shortened player objects
let p2 = {y:100}
var supers = {p1:[], p2:[]};
function draw(){
superProject();
if (p1.super.timeLeft >= 1 && p1.super.type == 'MISSILE'){
p1.super.timeLeft--;
let randY = Math.round(random(50, 150));
let missile = {x:40, y:randY, vel:p1.super.vel, dist:{x:0, y:0}}
supers.p1.push(missile);
}
}
function superProject(){
if (supers.p1.length > 0){
for (let i = 0; i < supers.p1.length; i++){
supers.p1[i].x += supers.p1[i].vel.x;
supers.p1[i].y += supers.p1[i].vel.y;
let distY = 0;
distY = p2.y - supers.p1[i].y;
let distX = 0;
distX = 170 - supers.p1[i].x
supers.p1[i].dist.x = distX;
supers.p1[i].dist.y = distY;
if (distY > 0){
supers.p1[i].vel.y += 1;
} else if (distY < 0){
supers.p1[i].vel.y -= 1;
}
circle(supers.p1[i].x, supers.p1[i].y, 4);
}
}
}
Link to full source. I would appreciate any help you can give me.
I am trying to draw a between two lines but arc is not rendering properly. I am using the following code:
imageContext- Canvas's Context
x1- starting point
y1-starting point
multiPointArr- Array which contains points of line(s)
imageContext.beginPath();
imageContext.moveTo(x1,y1);
if(multiPointArr.length==2)
imageContext.lineTo(x2,y2);
if(multiPointArr.length>2){
for( var ii=1 ; ii < multiPointArr.length ; ii++ ){
imageContext.lineTo(multiPointArr[ii].x,multiPointArr[ii].y);
}
}
imageContext.stroke();
if(multiPointArr.length==3)
{
imageContext.beginPath();
var xArr=[multiPointArr[0].x,multiPointArr[1].x,multiPointArr[2].x];
var yArr=[multiPointArr[0].y,multiPointArr[1].y,multiPointArr[2].y];
var m1 = Math.abs(Math.atan((yArr[1] - yArr[0])/(xArr[1] -xArr[0]))/Math.PI*180.0);
var m2 = Math.abs(Math.atan((yArr[1] - yArr[2])/(xArr[1] -xArr[2]))/Math.PI*180.0);
if(xArr[0] >= xArr[1])
{
if(yArr[0] >= yArr[1]);
else m1 = 360 - m1;
}
else
{
if(yArr[0] >= yArr[1])m1 = 180 - m1;
else m1 = 180 + m1;
}
if(xArr[2] >= xArr[1])
{
if(yArr[2] >= yArr[1]);
else m2 = 360 - m2;
}
else
{
if(yArr[2] >= yArr[1])m2 = 180 - m2;
else m2 = 180 + m2;
}
var arr=[];
arr[0] = Math.min(m1, m2);
arr[1] = Math.abs(m1 - m2);
arr[2] = arr[1];
if(arr[1] > 180)
{
arr[0] = Math.max(m1,m2);
arr[1] = 360 - arr[1];
}
arr[0]=(arr[0]*Math.PI)/180;
arr[1]=(arr[1]*Math.PI)/180;
arr[2]=(arr[2]*Math.PI)/180;
var ArcLen = 30;
imageContext.arc((xArr[1]),(yArr[1]),Math.abs(ArcLen*2),arr[0],arr[1],false);
imageContext.stroke();
}
Using above code arc is not drawing between lines.
It looks like following:
However starting angle is drawing correct but there is a problem with endAngle. Please let me know how I can resolve this problem.
So I wrote this code for a simple game. The code runs at 60 fps in both Chrome and Safari but Firefox barely manages 30-40 fps. The code looks simple enough to me. What could be causing the delay?
I checked in firebug and found out that only one function "follow" is taking up all the time. Here is the code:
function checkCollision (ball0, ball1) {
var dx = ball1.X - ball0.X,
dy = ball1.Y - ball0.Y,
dist = Math.sqrt(dx * dx + dy * dy);
if (dist < ball0.rad + ball1.rad) {
var angle = Math.atan2(dy, dx),
sin = Math.sin(angle),
cos = Math.cos(angle);
var pos0 = {x: 0, y: 0},
pos1 = rotate(dx, dy, sin, cos, true),
vel0 = rotate(ball0.spdX, ball0.spdY, sin, cos, true),
vel1 = rotate(ball1.spdX, ball1.spdY, sin, cos, true),
vxTotal = vel0.x - vel1.x;
vel0.x = ((ball0.mass - ball1.mass) * vel0.x + 2 * ball1.mass * vel1.x) /
(ball0.mass + ball1.mass);
vel1.x = vxTotal + vel0.x;
var absV = Math.abs(vel0.x) + Math.abs(vel1.x),
overlap = (ball0.rad + ball1.rad) - Math.abs(pos0.x - pos1.x);
pos0.x += vel0.x / absV * overlap;
pos1.x += vel1.x / absV * overlap;
//rotate positions back
var pos0F = rotate(pos0.x, pos0.y, sin, cos, false),
pos1F = rotate(pos1.x, pos1.y, sin, cos, false);
ball1.X = ball0.X + pos1F.x;
ball1.Y = ball0.Y + pos1F.y;
ball0.X = ball0.X + pos0F.x;
ball0.Y = ball0.Y + pos0F.y;
var vel0F = rotate(vel0.x, vel0.y, sin, cos, false),
vel1F = rotate(vel1.x, vel1.y, sin, cos, false);
ball0.spdX = vel0F.x;
ball0.spdY = vel0F.y;
ball1.spdX = vel1F.x;
ball1.spdY = vel1F.y;
}
}
function move()
{
var side,i;
for (i=0 ; i < balls.length; i++)
{
var obj = balls[i];
if (side=obj.edgeX())
{
if (side === 'l')
obj.X = obj.rad;
else if (side === 'r')
obj.X = canvas.width() - obj.rad;
obj.spdX*=-1;
}
if (side=obj.edgeY())
{
if (side === 't')
obj.Y = obj.rad;
else if (side === 'b')
obj.Y = canvas.height() - obj.rad;
obj.spdY*=-1;
}
if (leash == true && i === 0)
{
if (mouse.X>obj.X && (obj.spdX<10))
obj.spdX+=obj.accX;
else if (mouse.X<obj.X && (obj.spdX>-10))
obj.spdX-=obj.accX;
if (mouse.Y>obj.Y && (obj.spdY<10))
obj.spdY+=obj.accY;
else if (mouse.Y<obj.Y && (obj.spdY>-10))
obj.spdY-=obj.accY;
}
obj.X+=obj.spdX;
obj.Y+=obj.spdY;
if (Math.abs(obj.spdX)>0.1)
obj.spdX*=0.98;
else obj.spdX=0;
if (Math.abs(obj.spdY)>0.1)
obj.spdY*=0.98;
else obj.spdY = 0;
};
}
function follow()
{
var ballA, i, ballB,j;
requestAnimationFrame(follow);
//stats.begin();
context.clearRect(0,0,canvas.width(),canvas.height());
move();
for (i = 0, len = balls.length - 1; i < len; i++) {
ballA = balls[i];
for (j = i + 1; j < balls.length; j++) {
ballB = balls[j];
checkCollision(ballA, ballB);
}
}
balls.forEach(function(obj){
drawCircle(obj.X,obj.Y,obj.rad, obj.color);
if (leash == true && obj.control === true)
{drawLeash(mouse.X,mouse.Y,obj.X,obj.Y,obj.color);}
});
//stats.end();
};
Here is the animation: http://ipsumturpis.xtreemhost.com/follower/index.html
I vaguely remembered there used to be a problem in FF regarding with canvas drawing performance, so I have commented out drawCircle(obj.X,obj.Y,obj.rad, obj.color); and poof, magic happened - my frame rate went up from 11 FPS to 60.
Try caching balls length in a variable. Unless it’s absolutely necessary for reasons I don’t see, running balls.length (or any function) in every iteration of a loop is naturally going to be time consuming.
So try something like this;
ballslen = balls.length;
for (j = i + 1; j < ballslen; j++)
I was starting to teach myself how to work with HTML5 Canvas and decided to learn by making a short game/demo.
I wanted to make a simple blocks bounce around the screen, bounce off the walls, and bounce off each other.
I'm stuck on getting them to bounce off each other. It seems like code that makes it bounce away is making it bounce back immediately after. I see where the code fails but I don't know how to fix it :( Can anyone help?
(Side question: I know I'm not working as clean/efficiently/professionally as possible in this example but if I wanted to improve with feedback and opinions about the 'best' method for this type of example, like a code review or something, is it ok to ask a question on stackoverflow?)
jsfiddle:
http://jsfiddle.net/vdcSv/
HTML:
<canvas id="canvas" Width="400" Height="300"></canvas>
Javscript:
function CheckBallCollision(BallsArray, index) {
for (var i = 0; i < BallsArray.length; i++) {
if (index != i) {
if (BallsArray[index].Xdir == 1) {
if ((BallsArray[index].Xmax >= BallsArray[i].Xmin)) {
if ((BallsArray[index].Ymin <= BallsArray[i].Ymin) && (BallsArray[index].Ymax >= BallsArray[i].Ymin) ||
((BallsArray[index].Ymax >= BallsArray[i].Ymax) && (BallsArray[index].Ymin <= BallsArray[i].Ymax))) {
BallsArray[index].Xdir = -BallsArray[index].Xdir;
}
}
} else if (BallsArray[index].Xdir == -1) {
if ((BallsArray[index].Xmin <= BallsArray[i].Xmax)) {
if ((BallsArray[index].Ymin <= BallsArray[i].Ymin) && (BallsArray[index].Ymax >= BallsArray[i].Ymin) ||
((BallsArray[index].Ymax >= BallsArray[i].Ymax) && (BallsArray[index].Ymin <= BallsArray[i].Ymax))) {
BallsArray[index].Xdir = -BallsArray[index].Xdir;
}
}
}
}
}
}
Ball Object:
function Ball() {
this.Xmin = 0;//top left X coord
this.Ymin = 0;//top left y coord
this.Height = 25;
this.Width = 25;
this.Xmax = this.Xmin + this.Width;
this.Ymax = this.Ymin + this.Height;
this.Xdir = 0; // 0 not moving, 1 moving right, -1 moving left
this.Ydir = 0;
this.Red = 0;
this.Green = 0;
this.Blue = 200;
this.Opacity = 1;
this.Speed = 1;
}
Got it working by changing the <= to ==
It's messy and things often miss the necessary bounce off a block :( I'm sure part of the reason is falling back on the == instead of <=. If anyone has a better solution - I'm all ears :)
http://jsfiddle.net/vdcSv/1/
function CheckBallCollision(BallsArray, index) {
for (var i = 0; i < BallsArray.length; i++) {
if (index != i) {
if (BallsArray[index].Xdir == 1) {
if ((BallsArray[index].Xmax == BallsArray[i].Xmin)) {
if ((BallsArray[index].Ymin <= BallsArray[i].Ymin) && (BallsArray[index].Ymax >= BallsArray[i].Ymin) ||
((BallsArray[index].Ymax >= BallsArray[i].Ymax) && (BallsArray[index].Ymin <= BallsArray[i].Ymax))) {
BallsArray[index].Xdir = -BallsArray[index].Xdir;
}
}
} else if (BallsArray[index].Xdir == -1) {
if ((BallsArray[index].Xmin == BallsArray[i].Xmax)) {
if ((BallsArray[index].Ymin <= BallsArray[i].Ymin) && (BallsArray[index].Ymax >= BallsArray[i].Ymin) ||
((BallsArray[index].Ymax >= BallsArray[i].Ymax) && (BallsArray[index].Ymin <= BallsArray[i].Ymax))) {
BallsArray[index].Xdir = -BallsArray[index].Xdir;
}
}
}
}
}
}
Here are a couple hit detection snippets you might want to look into:
ball.hitTestCircle = function(obj) {
var dx = this.x - obj.x;
var dy = this.y - obj.y;
var distance = (dx * dx) + (dy * dy);
var area = (this.radius + obj.radius)*(this.radius + obj.radius);
return (area / distance);
};
if the call returns 1 or greater your colliding, and you can even use that info to fix the difference.
Here is basic rect hit detections script:
ball.hitTestRect = function(b) {
var difference = {};
difference.x = this.x - b.x - b.width;
difference.y = this.y - b.y - b.height;
difference.height = this.height + b.height;
difference.width = this.width + b.width;
if (difference.x < 0 && difference.y <= 0 && difference.height + difference.y >= 0 && difference.width + difference.x >= 0) return true;
return false;
};
I would call either of these with something like :
for(var i=0;i!=balls.length;i++){
for(var j=0;j!=balls.length;j++){
if(j!=i){
if(balls[i].hitTestRect(balls[j])){
// all your reversing motion code
}
}
}
}
It looks like you forgot to check if
BallsArray[index].Xmin <= BallsArray[i].Xmax)
If you add this in it works. It's also worth noting that you don't need different code for the two different X directions as this behaviour is symmetrical. Regardless of which way it is travelling to begin with you have it reversing direction. It's also symmetrical in the Y direction so if you just add:
BallsArray[index].Ydir = -BallsArray[index].Ydir;
to the 'then' part of the if you'll only need one if to take care of all four kinds of collisions.
You may also want to add a break statement so that if a ball happens to collide with two other balls at the same time it will only reverse direction once.
For a more realistic simulation you can multiply by a negative number in the (0, 1) interval, however if you don't do something else your system will slowly settle into a steady state until the rounding errors kick in and it freaks out.