﻿ Collision Detection Leading to Color Detection - ITCodar

# Collision Detection Leading to Color Detection

## Collision detection leading to color detection?

My suggestion is that your change your "pair" of walls to become a trio of walls instead. This third wall should have a different categoryBitMask. (`PhysicsCategory.wallSpace` seems to fit with your current naming scheme.)

This "wallSpace" needs to be positioned between the two existing walls. It should be given the same color as its siblings through your color-change logic, but here comes the trick: set it's alpha to 0.

This way you can check for collisions between this invisible wall and your ball and perform actions based on the color-information.

## How do I detect a collision with a color?

i do not recomend pixel collision, as it's uncecessary CPU and FPS killer.
here are some collsions that could help you. but if you really need pixel collision, first check rectange or any other collision detection and then if intersect then use pixel collsion to be preciesly... but I don't recomend that, especially in fast games.

POLYGON

http://www.codeproject.com/Articles/15573/2D-Polygon-Collision-Detection

CIRCLE:

``int circlesColliding(int x1,int y1,int radius1,int x2,int y2,int radius2){    //compare the distance to combined radii    int dx = x2 - x1;    int dy = y2 - y1;    int radii = radius1 + radius2;    if ( ( dx * dx )  + ( dy * dy ) < radii * radii )     {        return true;    }    else    {        return false;    }}``

CIRCLE TO RECTANGLE

``bool intersects(CircleType circle, RectType rect){    circleDistance.x = abs(circle.x - rect.x);    circleDistance.y = abs(circle.y - rect.y);    if (circleDistance.x > (rect.width/2 + circle.r)) { return false; }    if (circleDistance.y > (rect.height/2 + circle.r)) { return false; }    if (circleDistance.x <= (rect.width/2)) { return true; }     if (circleDistance.y <= (rect.height/2)) { return true; }    cornerDistance_sq = (circleDistance.x - rect.width/2)^2 +                         (circleDistance.y - rect.height/2)^2;    return (cornerDistance_sq <= (circle.r^2));}``

## Processing color collision detection (java)

This was a real head scratcher- good question.

The biggest thing throwing you off is the fact that Processing enables anti-aliasing by default. This causes your colors to be just a little different than what you expect. In most sketches, this is a good thing, since it makes things look better. But since you're using the exact color values, this is screwing you up. You can prove this by taking a screenshot of your sketch and then sampling your colors.

To disable this, simply call `noSmooth()` at the beginning of your sketch. More info can be found in the reference here.

The next thing screwing you up is that your stroke weight is set to 3, but you're only moving the players 1 pixel at a time. This causes the players to stay "inside" the last point that was drawn, which is why they're constantly running into themselves.

To fix that, you could simply call `strokeWeight(1);` at the beginning of the `draw()` function. Or if you need a stroke weight of 3, then make sure you move the player outside of the circle that was just drawn.

That'll fix your problem here, but in the long run, you'd probably be better off keeping track of previous player positions in a data structure like an `ArrayList` of `PVectors`. Then you'd redraw them each time `draw()` was called instead of only drawing them once. And instead of trying to check colors manually, it would be easier to do collision checks in only certain parts of the paths, to avoid the above case.

## Color collision detection in Pygame

You can create a `Mask` from a `Color`, using pygame.mask.from_threshold, and use the standard pygame colision detection.

Here's an example where I create a `Mask` using yellow:

``import pygameimport randomclass Circle(pygame.sprite.Sprite):    def __init__(self, pos, color, *grps):        super().__init__(*grps)        self.image = pygame.Surface((32, 32))        self.image.set_colorkey((1, 2, 3))        self.image.fill((1, 2, 3))        pygame.draw.circle(self.image, pygame.Color(color), (15, 15), 15)        self.rect = self.image.get_rect(center=pos)def main():    screen = pygame.display.set_mode((800, 600))    colors = ['green', 'yellow', 'white', 'blue']    sprites = pygame.sprite.Group()    objects = pygame.sprite.Group()    for _ in range(20):        pos = random.randint(100, 700), random.randint(100, 600)        Circle(pos, random.choice(colors), sprites, objects)    for sprite in objects:        sprite.mask = pygame.mask.from_threshold(sprite.image, pygame.Color('yellow'), (1, 1, 1, 255))    player = Circle(pygame.mouse.get_pos(), 'dodgerblue', sprites)    while True:        for e in pygame.event.get():            if e.type == pygame.QUIT:                 return        player.rect.center = pygame.mouse.get_pos()        if pygame.sprite.spritecollideany(player, objects, pygame.sprite.collide_mask):            screen.fill((255, 255, 255))        else:            screen.fill((30, 30, 30))        sprites.update()        sprites.draw(screen)        pygame.display.flip()main()`` ## Detecting collision with color on a canvas in HTML5+JavaScript

Well, I found a way to solve this issue :) Hopefully it helps someone...

``var box = {    x: 5,    y: 19,    width: 10,    height: 5,    draw: function(ctx){...draw Box on context "ctx"},    touchingColor: function(ctx,r,g,b){        var data = ctx.getImageData(this.x,this.y,this.width,this.height);        for(var i=0;i<data.length;i+=4){            if(                data[i+0]==r&&                data[i+1]==g&&                data[i+2]==b            ){                return true;            }        }        return false;    }};``

## Detecting when two of the same colors collide

First thing you should do is set up the contactTestBitMasks & categoryBitMasks on all of your SKSpriteNodes, like this -

``struct PhysicsCatagory {    static let FirstPerson : UInt32 = 0x1 << 1    static let SecondPerson : UInt32 = 0x1 << 2} override func didMoveToView(view: SKView) {     ...     firstPerson.SKPhysicsBody?.catagoryBitMask = PhysicsCatagory.FirstPerson     firstPerson.SKPhysicsBody?.contactTestBitMask = PhysicsCatagory.SecondPerson     ...     secondPerson.SKPhysicsBody?.catagoryBitMask = PhysicsCatagory.SecondPerson     secondPerson.SKPhysicsBody?.contactTestBitMask = PhysicsCatagory.FirstPerson     ...}``

This is just setting up the catagoryBitMask and the contactTestBitMask. The categoryBitMask will be equal to the object you are currently editing, whereas, the contactTestBitMask will be equal to the object you want the object to collide with.

Also, before we move on, we want to add the Contact Delegate to our scene.

``class GameScene: SKScene, SKPhysicsContactDelegate{...``

And then add the delegate to our scene -

``override func didMoveToView(view: SKView) {      ...       self.physicsWorld.contactDelegate = self      ...``

``func didBeginContact(contact: SKPhysicsContact) {    let firstBody = contact.bodyA.node as! SKSpriteNode!    let secondBody = contact.bodyB.node as! SKSpriteNode!}``

Lastly inside of that, test...

``func didBeginContact(contact: SKPhysicsContact) {    let firstBody = contact.bodyA.node as! SKSpriteNode!    let secondBody = contact.bodyB.node as! SKSpriteNode!    if firstBody.color == secondBody.color{     firstBody.removeFromParent()     secondBody.removeFromParent()}}``

Hope that helps! :D

## How to change color of circle when collision detection occurs?

#### Semaphores

Use a semaphore that holds the collision state of the circle.

Thus in your `Circle.prototype` would have something like these functions and properties

``Circle.prototype = {    collided: false,  // when true change color    draw() {        ctx.strokeStyle = this.collided ? "red" : "blue";        ctx.lineWidth = 3;        ctx.beginPath();        ctx.arc(this.x, this.y, this.r - 1.5, 0, Math.PI * 2);        ctx.stroke();    },    ...    ...    // in update     update() {        // when collision is detected set semaphore        if (collision) {            this.collided = true;        }    }}``

#### Counters

Or you may want to only have the color change last for some time. You can modify the semaphore and use it as a counter. On collision set it to the number of frames to change color for.

``Circle.prototype = {    collided: 0,    draw() {        ctx.strokeStyle = this.collided ? (this.collided--, "red") : "blue";        ctx.lineWidth = 3;        ctx.beginPath();        ctx.arc(this.x, this.y, this.r - 1.5, 0, Math.PI * 2);        ctx.stroke();    },    ...    ...    // in update     update() {        // when collision is detected set semaphore        if (collision) {            this.collided = 60;  // 1 second at 60FPS        }    }}``

#### Example

This example is taken from another answer I did earlier this year.

As there is a lot of code I have highlighted the relevant code with

``/*= ANSWER CODE ==============================================================...=============================================================================*/``

The example uses counters and changes color for 30 frames after a collision with another ball or wall.

I did not use a semaphore as all the balls would be red within a second.

``canvas.width = innerWidth -20;canvas.height = innerHeight -20;mathExt(); // creates some additional math functionsconst ctx = canvas.getContext("2d");const GRAVITY = 0;const WALL_LOSS = 1;const BALL_COUNT = 10;  // approx as will not add ball if space can not be foundconst MIN_BALL_SIZE = 6;const MAX_BALL_SIZE = 30;const VEL_MIN = 1;const VEL_MAX = 5; const MAX_RESOLUTION_CYCLES = 100; // Put too many balls (or too large) in the scene and the                                    // number of collisions per frame can grow so large that                                   // it could block the page.                                   // If the number of resolution steps is above this value                                   // simulation will break and balls can pass through lines,                                   // get trapped, or worse. LOLconst SHOW_COLLISION_TIME = 30;const balls = [];const lines = [];function Line(x1,y1,x2,y2) {    this.x1 = x1;    this.y1 = y1;    this.x2 = x2;    this.y2 = y2;}Line.prototype = {    draw() {        ctx.moveTo(this.x1, this.y1);        ctx.lineTo(this.x2, this.y2);    },    reverse() {        const x = this.x1;        const y = this.y1;        this.x1 = this.x2;        this.y1 = this.y2;        this.x2 = x;        this.y2 = y;        return this;    }}    function Ball(x, y, vx, vy, r = 45, m = 4 / 3 * Math.PI * (r ** 3)) {    this.r = r;    this.m = m    this.x = x;    this.y = y;    this.vx = vx;    this.vy = vy;    /*= ANSWER CODE ==============================================================*/    this.collided = 0;    /*============================================================================*/}Ball.prototype = {    update() {        this.x += this.vx;        this.y += this.vy;        this.vy += GRAVITY;    },    draw() {        /*= ANSWER CODE ==============================================================*/        ctx.strokeStyle = this.collided ? (this.collided--, "#F00") : "#00F";        ctx.lineWidth = 3;        ctx.beginPath();        ctx.arc(this.x, this.y, this.r - 1.5, 0, Math.PI * 2);        ctx.stroke();       /* ============================================================================*/    },    interceptLineTime(l, time) {        const u = Math.interceptLineBallTime(this.x, this.y, this.vx, this.vy, l.x1, l.y1, l.x2, l.y2,  this.r);        if (u >= time && u <= 1) {            return u;        }    },    checkBallBallTime(t, minTime) {        return t > minTime && t <= 1;    },    interceptBallTime(b, time) {        const x = this.x - b.x;        const y = this.y - b.y;        const d = (x * x + y * y) ** 0.5;        if (d > this.r + b.r) {            const times = Math.circlesInterceptUnitTime(                this.x, this.y,                 this.x + this.vx, this.y + this.vy,                 b.x, b.y,                b.x + b.vx, b.y + b.vy,                 this.r, b.r            );            if (times.length) {                if (times.length === 1) {                    if(this.checkBallBallTime(times, time)) { return times }                    return;                }                if (times <= times) {                    if(this.checkBallBallTime(times, time)) { return times }                    if(this.checkBallBallTime(times, time)) { return times }                    return                }                if(this.checkBallBallTime(times, time)) { return times }                                if(this.checkBallBallTime(times, time)) { return times }            }        }    },    collideLine(l, time) {                /*= ANSWER CODE ==============================================================*/        this.collided = SHOW_COLLISION_TIME;        /*============================================================================*/        const x1 = l.x2 - l.x1;        const y1 = l.y2 - l.y1;        const d = (x1 * x1 + y1 * y1) ** 0.5;        const nx = x1 / d;        const ny = y1 / d;                    const u = (this.vx  * nx + this.vy  * ny) * 2;        this.x += this.vx * time;           this.y += this.vy * time;           this.vx = (nx * u - this.vx) * WALL_LOSS;        this.vy = (ny * u - this.vy) * WALL_LOSS;        this.x -= this.vx * time;        this.y -= this.vy * time;    },    collide(b, time) { // b is second ball        /*= ANSWER CODE ==============================================================*/        this.collided = SHOW_COLLISION_TIME;        b.collided = SHOW_COLLISION_TIME;        /*============================================================================*/        const a = this;        const m1 = a.m;        const m2 = b.m;        a.x = a.x + a.vx * time;        a.y = a.y + a.vy * time;        b.x = b.x + b.vx * time;        b.y = b.y + b.vy * time;                const x = a.x - b.x        const y = a.y - b.y          const d = (x * x + y * y);        const u1 = (a.vx * x + a.vy * y) / d        const u2 = (x * a.vy - y * a.vx ) / d        const u3 = (b.vx * x + b.vy * y) / d        const u4 = (x * b.vy - y * b.vx ) / d        const mm = m1 + m2;        const vu3 = (m1 - m2) / mm * u1 + (2 * m2) / mm * u3;        const vu1 = (m2 - m1) / mm * u3 + (2 * m1) / mm * u1;        b.vx = x * vu1 - y * u4;        b.vy = y * vu1 + x * u4;        a.vx = x * vu3 - y * u2;        a.vy = y * vu3 + x * u2;        a.x = a.x - a.vx * time;        a.y = a.y - a.vy * time;        b.x = b.x - b.vx * time;        b.y = b.y - b.vy * time;    },    doesOverlap(ball) {        const x = this.x - ball.x;        const y = this.y - ball.y;        return  (this.r + ball.r) > ((x * x + y * y) ** 0.5);      }       }function canAdd(ball) {    for(const b of balls) {        if (ball.doesOverlap(b)) { return false }    }    return true;}function create(bCount) {    lines.push(new Line(-10, 20, ctx.canvas.width + 10, 5));    lines.push((new Line(-10, ctx.canvas.height - 2, ctx.canvas.width + 10, ctx.canvas.height - 30)).reverse());    lines.push((new Line(30, -10, 4, ctx.canvas.height + 10)).reverse());    lines.push(new Line(ctx.canvas.width - 3, -10, ctx.canvas.width - 30, ctx.canvas.height + 10));     while (bCount--) {        let tries = 100;        while (tries--) {            const dir = Math.rand(0, Math.TAU);            const vel = Math.rand(VEL_MIN, VEL_MAX);            const ball = new Ball(                Math.rand(MAX_BALL_SIZE + 30, canvas.width - MAX_BALL_SIZE - 30),                 Math.rand(MAX_BALL_SIZE + 30, canvas.height - MAX_BALL_SIZE - 30),                Math.cos(dir) * vel,                Math.sin(dir) * vel,                Math.rand(MIN_BALL_SIZE, MAX_BALL_SIZE),            );            if (canAdd(ball)) {                balls.push(ball);                break;            }        }    }}function resolveCollisions() {    var minTime = 0, minObj, minBall, resolving = true, idx = 0, idx1, after = 0, e = 0;    while (resolving && e++ < MAX_RESOLUTION_CYCLES) { // too main ball may create very lone resolution cycle. e limits this        resolving = false;        minObj = undefined;        minBall = undefined;        minTime = 1;        idx = 0;        for (const b of balls) {            idx1 = idx + 1;            while (idx1 < balls.length) {                const b1 = balls[idx1++];                const time = b.interceptBallTime(b1, after);                if (time !== undefined) {                    if (time <= minTime) {                        minTime = time;                        minObj = b1;                        minBall = b;                        resolving = true;                    }                }            }            for (const l of lines) {                const time = b.interceptLineTime(l, after);                if (time !== undefined) {                    if (time <= minTime) {                        minTime = time;                        minObj = l;                        minBall = b;                        resolving = true;                    }                }            }            idx ++;        }        if (resolving) {            if (minObj instanceof Ball) {                minBall.collide(minObj, minTime);            } else {                minBall.collideLine(minObj, minTime);            }            after = minTime;        }    }}create(BALL_COUNT);mainLoop();function mainLoop() {    ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);    resolveCollisions();    for (const b of balls) { b.update() }    for (const b of balls) { b.draw() }    ctx.lineWidth = 1;    ctx.strokeStyle = "#000";    ctx.beginPath();    for(const l of lines) { l.draw() }    ctx.stroke();    requestAnimationFrame(mainLoop);}function mathExt() {    Math.TAU = Math.PI * 2;    Math.rand = (min, max) => Math.random() * (max - min) + min;    Math.randI = (min, max) => Math.random() * (max - min) + min | 0; // only for positive numbers 32bit signed int    Math.randItem = arr => arr[Math.random() * arr.length | 0]; // only for arrays with length < 2 ** 31 - 1    // contact points of two circles radius r1, r2 moving along two lines (a,e)-(b,f) and (c,g)-(d,h) [where (,) is coord (x,y)]    Math.circlesInterceptUnitTime = (a, e, b, f, c, g, d, h, r1, r2) => { // args (x1, y1, x2, y2, x3, y3, x4, y4, r1, r2)        const A = a * a, B = b * b, C = c * c, D = d * d;        const E = e * e, F = f * f, G = g * g, H = h * h;        var R = (r1 + r2) ** 2;        const AA = A + B + C + F + G + H + D + E + b * c + c * b + f * g + g * f + 2 * (a * d - a * b - a * c - b * d - c * d - e * f + e * h - e * g - f * h - g * h);        const BB = 2 * (-A + a * b + 2 * a * c - a * d - c * b - C + c * d - E + e * f + 2 * e * g - e * h - g * f - G + g * h);        const CC = A - 2 * a * c + C + E - 2 * e * g + G - R;        return Math.quadRoots(AA, BB, CC);    }       Math.quadRoots = (a, b, c) => { // find roots for quadratic        if (Math.abs(a) < 1e-6) { return b != 0 ? [-c / b] : []  }        b /= a;        var d = b * b - 4 * (c / a);        if (d > 0) {            d = d ** 0.5;            return  [0.5 * (-b + d), 0.5 * (-b - d)]        }        return d === 0 ? [0.5 * -b] : [];    }    Math.interceptLineBallTime = (x, y, vx, vy, x1, y1, x2, y2,  r) => {        const xx = x2 - x1;        const yy = y2 - y1;        const d = vx * yy - vy * xx;        if (d > 0) {  // only if moving towards the line            const dd = r / (xx * xx + yy * yy) ** 0.5;            const nx = xx * dd;            const ny = yy * dd;            return (xx * (y - (y1 + nx)) - yy * (x -(x1 - ny))) / d;        }    }}``
``<canvas id="canvas"></canvas>``

## can you make it so when two colors collide with each other the game ends?

Well if you just need to check whether any of the rectangles have collided with the player then you can simply add them all to a list and go through that list checking each one for a collision.
Something like this should work:

``import pygameimport timeblack = (0, 0, 0)white = (255, 255, 255)red = (255, 0, 0)green = (0, 255, 0)pygame.init()size = (610, 410)screen = pygame.display.set_mode(size)pygame.display.set_caption("Maze Game")screen.fill(white)pygame.display.flip()x = 20y = 360x_speed = 0y_speed = 0def cube(x, y):    c = pygame.Rect(x + x_speed, y + y_speed, 30, 30)    pygame.draw.rect(screen, red,[x + x_speed, y + y_speed, 30, 30])    return crects = []def rectangles():    #pygame.Rect([0, 0, 610, 410], 10)    #border wasnt working as one of these but works further down#    # add them all to a list    rects.append(pygame.Rect(50, 60, 50, 340))    rects.append(pygame.Rect(100, 60, 50, 50))    rects.append(pygame.Rect(200, 10, 50, 300))    rects.append(pygame.Rect(250, 10, 50, 50))    rects.append(pygame.Rect(150, 150, 50, 200))    rects.append(pygame.Rect(300, 100, 50, 50))    rects.append(pygame.Rect(200, 300, 100, 50))    rects.append(pygame.Rect(350, 60, 50, 340))    rects.append(pygame.Rect(250, 200, 50, 100))    rects.append(pygame.Rect(450, 10, 50, 340))    rects.append(pygame.Rect(550, 60, 50, 340))def gameover():    font = pygame.font.SysFont(None, 55)    text = font.render("Game Over! Play Again? (y or n)", True, green)    screen.blit(text, [20, 250])    pygame.display.flip()    done = False    while (done == False):        for event in pygame.event.get():            if (event.type == pygame.QUIT):                pygame.quit()            elif(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):                pygame.quit()            if(event.type == pygame.KEYDOWN):                if(event.key == pygame.K_y):                    board1()            if(event.type == pygame.KEYDOWN):                if (event.key == pygame.K_n):                    pygame.quit()def board1():    x = 15     y = 360    x_speed = 0    y_speed = 0    done = False    while (not done):        for event in pygame.event.get():            if (event.type == pygame.QUIT):                pygame.quit()            elif(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):                pygame.quit()            if(event.type == pygame.KEYDOWN):                if(event.key == pygame.K_UP):                    y_speed = -.1                if(event.key == pygame.K_DOWN):                    y_speed = .1                if(event.key == pygame.K_LEFT):                    x_speed = -.1                if(event.key == pygame.K_RIGHT):                    x_speed = .1            if(event.type == pygame.KEYUP):                if (event.key == pygame.K_UP):                    y_speed = 0                if (event.key == pygame.K_DOWN):                    y_speed = 0                if (event.key == pygame.K_LEFT):                    x_speed = 0                if (event.key == pygame.K_RIGHT):                    x_speed = 0        screen.fill(white)        c = cube(x, y)        r = rectangles()        pygame.draw.rect(screen, black, [0, 0, 610, 410], 10)        pygame.draw.rect(screen, black, [50, 60, 50, 340])        pygame.draw.rect(screen, black, [100, 60, 50, 50])        pygame.draw.rect(screen, black, [200, 10, 50, 300])        pygame.draw.rect(screen, black, [250, 10, 50, 50])        pygame.draw.rect(screen, black, [150, 150, 50, 200])        pygame.draw.rect(screen, black, [300, 100, 50, 50])        pygame.draw.rect(screen, black, [200, 300, 100, 50])        pygame.draw.rect(screen, black, [350, 60, 50, 340])        pygame.draw.rect(screen, black, [250, 200, 50, 100])        pygame.draw.rect(screen, black, [450, 10, 50, 340])        pygame.draw.rect(screen, black, [550, 60, 50, 340])                pygame.display.flip()        x = x + x_speed        y = y + y_speed        # Check for each one of the walls        for rect in rects:            if c.colliderect(rect):                print("collision")                gameover()board1()``

However if you do want to detect by colour, its a bit more complex, but you can take a look at this:
Color collision detection in Pygame.