Talking about Game development, HTML5, Javascript and Phaser.
As a part in a bigger project – which you will hear about soon – I needed to find a quick way to check for collisions between a line segment and a circle. It’s quite an easy task, but man, I found a lot of really weird ways to do it, so here’s my take, based on this Stack Overflow question: Drag circle center or any of the two segment ends to change and update the result. The algorithm works by first finding the point on the line segment which is the closest to circle’s center. Then we compare the distance with the circle radius. If the distance is smaller than the radius, the circle is colliding with the line segment. Here is the source code:
var game;
var gameOptions = {
circleRadius: 50
}
window.onload = function() {
var gameConfig = {
thpe: Phaser.CANVAS,
width: 600,
height: 600,
scene: [playGame]
}
game = new Phaser.Game(gameConfig);
window.focus()
}
class playGame extends Phaser.Scene{
constructor(){
super("PlayGame");
}
preload(){
this.load.image("crosshair", "crosshair.png");
}
create(){
this.graphics = this.add.graphics();
this.circleCenter = this.add.sprite(Phaser.Math.Between(50, game.config.width - 50), Phaser.Math.Between(50, game.config.height - 50), "crosshair");
this.circleCenter.setInteractive();
this.segmentStart = this.add.sprite(Phaser.Math.Between(20, game.config.width - 20), Phaser.Math.Between(20, game.config.height - 20), "crosshair");
this.segmentStart.setInteractive();
this.segmentEnd = this.add.sprite(Phaser.Math.Between(20, game.config.width - 20), Phaser.Math.Between(20, game.config.height - 20), "crosshair");
this.segmentEnd.setInteractive();
this.input.setDraggable([this.circleCenter, this.segmentStart, this.segmentEnd]);
this.distancePoint = this.add.sprite(0, 0, "crosshair");
this.text = this.add.text(0, 0, "",{
fontFamily: "Arial",
color: "#ffffff"
});
this.drawStuff();
this.input.on("drag", function(pointer, gameObject, dragX, dragY) {
gameObject.x = dragX;
gameObject.y = dragY;
this.drawStuff();
}, this);
}
drawStuff(){
this.graphics.clear();
if(this.distToSegmentSquared({
x: this.circleCenter.x,
y: this.circleCenter.y
}, gameOptions.circleRadius, {
x: this.segmentStart.x,
y: this.segmentStart.y
}, {
x: this.segmentEnd.x,
y: this.segmentEnd.y
})){
this.graphics.lineStyle(2, 0x880000);
}
else{
this.graphics.lineStyle(2, 0x008800);
}
this.graphics.strokeCircle(this.circleCenter.x, this.circleCenter.y, gameOptions.circleRadius);
this.graphics.lineStyle(2, 0x008800);
this.graphics.beginPath();
this.graphics.moveTo(this.segmentStart.x, this.segmentStart.y);
this.graphics.lineTo(this.segmentEnd.x, this.segmentEnd.y);
this.graphics.closePath();
this.graphics.strokePath();
this.graphics.lineStyle(2, 0x888800);
this.graphics.beginPath();
this.graphics.moveTo(this.distancePoint.x, this.distancePoint.y);
this.graphics.lineTo(this.circleCenter.x, this.circleCenter.y);
this.graphics.closePath();
this.graphics.strokePath();
this.text.setText("Segment: (" + this.segmentStart.x + ", " + this.segmentStart.y +") to (" + this.segmentEnd.x + ", " + this.segmentEnd.y +")\nCircle center: (" + this.circleCenter.x + ", " + this.circleCenter.y +")\nPoint to watch: (" + this.distancePoint.x + ", " + this.distancePoint.y +")");
}
getDistance(p1, p2){
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
distToSegmentSquared(circleCenter, circleRadius, segmentStart, segmentEnd){
var l2 = this.getDistance(segmentStart, segmentEnd);
var t = ((circleCenter.x - segmentStart.x) * (segmentEnd.x - segmentStart.x) + (circleCenter.y - segmentStart.y) * (segmentEnd.y - segmentStart.y)) / l2;
t = Math.max(0, Math.min(1, t));
var tX = segmentStart.x + t * (segmentEnd.x - segmentStart.x);
var tY = segmentStart.y + t * (segmentEnd.y - segmentStart.y);
var tPoint = {
x: tX,
y: tY
}
this.distancePoint.x = Math.round(tX);
this.distancePoint.y = Math.round(tY);
return this.getDistance(circleCenter, tPoint) < circleRadius * circleRadius;
}
}
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.