diff --git a/package.json b/package.json index df343ea5..2a6e1ea7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@next2d/player", - "version": "2.7.0", + "version": "2.8.0", "description": "Experience the fast and beautiful anti-aliased rendering of WebGL. You can create rich, interactive graphics, cross-platform applications and games without worrying about browser or device compatibility.", "author": "Toshiyuki Ienaga (https://github.com/ienaga/)", "license": "MIT", diff --git a/packages/display/src/Shape/usecase/ShapeHitTestUseCase.test.ts b/packages/display/src/Shape/usecase/ShapeHitTestUseCase.test.ts index a5937d0a..c506f818 100644 --- a/packages/display/src/Shape/usecase/ShapeHitTestUseCase.test.ts +++ b/packages/display/src/Shape/usecase/ShapeHitTestUseCase.test.ts @@ -180,4 +180,247 @@ describe("ShapeHitTestUseCase.js test", () => expect(typeof result).toBe("boolean"); }); + + it("execute test case11 - hit inside shape without buffer (default rectangle path)", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 100; + shape.graphics.yMax = 100; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 50, y: 50 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case12 - hit outside shape without buffer", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 100; + shape.graphics.yMax = 100; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 150, y: 150 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(result).toBe(false); + }); + + it("execute test case13 - hit on edge of shape without buffer", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 100; + shape.graphics.yMax = 100; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 0, y: 0 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case14 - hit with shape transformation (rawMatrix)", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 50; + shape.graphics.yMax = 50; + shape.x = 50; + shape.y = 50; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 75, y: 75 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case15 - hit with scaled shape transformation", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 50; + shape.graphics.yMax = 50; + shape.scaleX = 2; + shape.scaleY = 2; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 75, y: 75 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case16 - hit with rotated shape", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 100; + shape.graphics.yMax = 100; + shape.rotation = 45; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 50, y: 50 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case17 - hit with combined parent matrix and shape transformation", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 50; + shape.graphics.yMax = 50; + shape.x = 10; + shape.y = 10; + + const parentMatrix = new Float32Array([1, 0, 0, 1, 100, 100]); + const hitObject = { x: 125, y: 125 }; + + const result = execute(shape, context, parentMatrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case18 - hit with graphics buffer", () => + { + const shape = new Shape(); + shape.graphics.beginFill(0xFF0000); + shape.graphics.drawRect(0, 0, 100, 100); + shape.graphics.endFill(); + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 50, y: 50 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case19 - hit outside with graphics buffer", () => + { + const shape = new Shape(); + shape.graphics.beginFill(0xFF0000); + shape.graphics.drawRect(0, 0, 100, 100); + shape.graphics.endFill(); + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 150, y: 150 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case20 - hit with line stroke graphics buffer", () => + { + const shape = new Shape(); + shape.graphics.lineStyle(5, 0x000000); + shape.graphics.moveTo(0, 0); + shape.graphics.lineTo(100, 100); + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 50, y: 50 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case21 - hit with circle graphics buffer", () => + { + const shape = new Shape(); + shape.graphics.beginFill(0x00FF00); + shape.graphics.drawCircle(50, 50, 50); + shape.graphics.endFill(); + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 50, y: 50 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case22 - handles negative coordinates", () => + { + const shape = new Shape(); + shape.graphics.xMin = -50; + shape.graphics.yMin = -50; + shape.graphics.xMax = 50; + shape.graphics.yMax = 50; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 0, y: 0 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case23 - handles fractional coordinates", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0.5; + shape.graphics.yMin = 0.5; + shape.graphics.xMax = 100.5; + shape.graphics.yMax = 100.5; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 50.25, y: 50.25 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case24 - handles very small shape", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 1; + shape.graphics.yMax = 1; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 0.5, y: 0.5 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); + + it("execute test case25 - handles very large shape", () => + { + const shape = new Shape(); + shape.graphics.xMin = 0; + shape.graphics.yMin = 0; + shape.graphics.xMax = 10000; + shape.graphics.yMax = 10000; + + const matrix = new Float32Array([1, 0, 0, 1, 0, 0]); + const hitObject = { x: 5000, y: 5000 }; + + const result = execute(shape, context, matrix, hitObject); + + expect(typeof result).toBe("boolean"); + }); }); diff --git a/packages/display/src/Shape/usecase/ShapeHitTestUseCase.ts b/packages/display/src/Shape/usecase/ShapeHitTestUseCase.ts index 0d6c917d..49d4489a 100644 --- a/packages/display/src/Shape/usecase/ShapeHitTestUseCase.ts +++ b/packages/display/src/Shape/usecase/ShapeHitTestUseCase.ts @@ -42,9 +42,25 @@ export const execute = ( tMatrix[3], tMatrix[4], tMatrix[5] ); - const hit = graphicsHitTestService( - hit_context, graphics.buffer, hit_object - ); + let hit = false; + if (graphics.buffer.length) { + hit = graphicsHitTestService( + hit_context, graphics.buffer, hit_object + ); + } else { + hit_context.setTransform( + tMatrix[0], tMatrix[1], tMatrix[2], + tMatrix[3], tMatrix[4], tMatrix[5] + ); + hit_context.beginPath(); + hit_context.moveTo(0, 0); + hit_context.lineTo(width, 0); + hit_context.lineTo(width, height); + hit_context.lineTo(0, height); + hit_context.lineTo(0, 0); + + hit = hit_context.isPointInPath(hit_object.x, hit_object.y); + } if (tMatrix !== matrix) { Matrix.release(tMatrix); diff --git a/src/index.ts b/src/index.ts index 42df8738..4e50c90e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ import { Next2D } from "@next2d/core"; if (!("next2d" in window)) { - console.log("%c Next2D Player %c 2.7.0 %c https://next2d.app", + console.log("%c Next2D Player %c 2.8.0 %c https://next2d.app", "color: #fff; background: #5f5f5f", "color: #fff; background: #4bc729", "");