Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
501 views
in Technique[技术] by (71.8m points)

html - HTML5 / kineticJS getIntersection function implementation

I am learning kineticjs through tutorials provided at http://www.html5canvastutorials.com, things are good and easy to understand but, I am having issue in understanding the getIntersection function that i want to use among different objects while dragging to detect collision / overlapping objects.

As far as I have understood the example the getIntersection function expects a position and checks if its intersecting with any other object or not..

Though I got them but with some issues.

I am unable to accomplish this..

Below is the code that I have tried up to now..

<script>

var stage = new Kinetic.Stage({
    container: 'container',
    width: 1000,
    height: 500,
    opacity: 0.5
});

var layer = new Kinetic.Layer();
var previous_position;
var new_position;
var collision = false;
var colors = ['red', 'orange', 'yellow', 'green', 'blue', 'purple'];
var yellowBox = null;
for(var n = 0; n < 6; n++) {
    // anonymous function to induce scope
    (function() {
        var i = n;
        if(n < 3){
            y = 50;
            x = i * 100 + i * 10;
        }else{
            y = 150;
            x = (i - 3) * 100 + (i - 3) * 10 ;
            if(n == 3){
                x = 0;
            }

        }
        var box = new Kinetic.Rect({
            x: x,
            y: y,
            width: 100,
            height: 50,
            fill: colors[i],
            stroke: 'black',
            strokeWidth: 4,
            draggable: true,
            name: colors[i]
        });

        box.on('dragstart', function() {
            previous_position =     {
                                        x: this.attrs.x,
                                        y: this.attrs.y 
                                    }; 
        });

        box.on('dragend', function() {
            if(collision){
                //this.setPosition(previous_position);
                layer.draw();
                collision = false;
            }else{
                //this.setPosition(new_position);
                layer.draw();
            }
        });

        box.on("dragmove", function(evt) {
            console.log(layer.children.length);
            if(layer.children.length > 1){
                console.log('dragging');
                new_position = {x: this.attrs.x,
                            y: this.attrs.y};
        //              var posBL = {x: this.attrs.x,
        //                          y: this.attrs.height + this.attrs.y};
        //              var posTR = {x: this.attrs.x    + this.attrs.width,
        //                          y: this.attrs.y};
                var posBR = {x: this.attrs.x    + this.attrs.width,
                            y: this.attrs.y + this.attrs.height };
                var collisionTL = this.getStage().getIntersections(new_position);
        //              var collisionBL = this.getStage().getIntersections(posBL);
        //              var collisionTR = this.getStage().getIntersections(posTR);
        //              var collisionBR = this.getStage().getIntersections(posBR);

                console.log(collisionTL);
                console.log(collisionTL.shapes);

        //              if(collisionTL.length > 1 || collisionBL.length > 0 || collisionTR.length > 0 || collisionBR.length > 0){
                if(collisionTL.length > 1){
                    console.log(collisionTL.shapes);
                    collision = true;
                }else{ //if(collisionBR.length > 0){
                    collision = true;
                }
        //              for(i=0; i < collision.length; i++){
        //              //  console.log(collision[i]._id);
        //              }
            }
        });


        if(colors[i] === 'yellow') {
            yellowBox = box;
        }

        layer.add(box);
    })();
}

stage.add(layer);

</script>

in the dragmove event you guyz can see I get the four corner positions of the dragging box {commented right now} and with this I was able to detect the overlap / collision but it has 2 issues:

1. very slow with only 3 objects in my test

2. if non of the corner points intersect it didn't fire the collision stuff {for this one box can be bigger so it can cover the other entirely}

I would highly apreciate if anyone can please help me accomplish this stuff..

[A] Any object dragging if by any mean overlaps any other object I want it to show collision.

[B] If possible make getIntersection to work on a particular layer group whichever is possible [C] any other workaround beside kineticJS to accomplish the above task

Regards

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Ok, the developer of KineticJS is working on improving the .getIntersections() function... or at least he said he is. But until the function is improved you have to make your own collision detection function. Assuming that your objects are rectangles or can be broken into a series of points you should go with something like this:

Create a function which determines if a point is in a shape (if the corner of a rectangle is inside another rectangle) like so:

 function checkCollide(pointX, pointY, objectx, objecty, objectw, objecth) { // pointX, pointY belong to one rectangle, while the object variables belong to another rectangle
      var oTop = objecty;
      var oLeft = objectx; 
      var oRight = objectx+objectw;
      var oBottom = objecty+objecth; 

      if(pointX > oLeft && pointX < oRight){
           if(pointY > oTop && pointY < oBottom ){
                return 1;
           }
      }
      else
           return 0;
 };

then you can do a big loop which iterates through all objects in a layer to check collision, like so:

 var children = layer.getChildren();
 for( var i=0; i<children.length; i++){  // for each single shape
     for( var j=0; j<children.length; j++){ //check each other shape
         if(i != j){ //skip if shape is the same
            if(checkCollide(children[i].getX(), children[i].getY(), children[j].getX(), children[j].getY(), children[j].getWidth(), children[j].getHeight()))
                alert('top left corner collided');
         }
     }
 }

the checkCollide function I provided only checks the collision for the top left corner on each shape, so you have to modify the function to check all corners, it's not a long rewrite, and there are plenty tutorials even here on stackoverflow which deal with 'bounding rectangles collision detection'

This may seem like it is a very heavy function, but surprisingly it is still faster than .getIntersections(). Also, you should throw in extra if statements so that the function doesn't run through all the checks all the time.

I created a game myself and was using .intersects() and was having a lot of slow down. I switched over to this type of 'simpler' collision detection and now my game runs around 60FPS. http://cs.neiu.edu/~tsam/physics/index.phtml (test/test) if you want to check it out. You can view page source to see how I structured the collision detection to be more efficient (such as in checkIntersectsGoal() function.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...