import Color from "/src/engine/data-structure/color.js";
import Vector from "/src/engine/data-structure/vector.js";
import GameObject from "/src/engine/core/game-object.js";
import { typeCheck, typeCheckAndClamp } from "/src/engine/utils.js";
/**
* 화면에 사각형을 그리는 객체다.
*
* @extends {GameObject}
*/
class Rect extends GameObject {
/**
* @constructor
* @param {object} options
* @param {string} [options.name]
* @param {number} [options.width]
* @param {number} [options.height]
* @param {boolean} [options.isActive]
* @param {boolean} [options.isVisible]
* @param {Layer} [options.layer]
* @param {Color} [options.color=Random Color]
* @param {boolean} [options.isPhysicsEnable=false]
* @param {object} [options.boundary]
* @param {number} [options.boundary.width]
* @param {number} [options.boundary.height]
* @param {number} [options.boundary.offset]
* @param {object} [options.transform]
* @param {Vector} [options.transform.position=new Vector(0, 0)]
* @param {Vector} [options.transform.scale=new Vector(1, 1)]
* @param {number} [options.transform.rotation=0]
* @param {object} [options.rigidbody]
* @param {number} [options.rigidbody.mass=1]
* @param {number} [options.rigidbody.bounceness=0.5]
* @param {number} [options.rigidbody.staticFriction=0.2]
* @param {number} [options.rigidbody.dynamicFriction=0.1]
* @param {boolean} [options.rigidbody.isStatic=false]
* @param {boolean} [options.rigidbody.isGravity=false]
* @param {boolean} [options.rigidbody.isTrigger=false]
*/
constructor(options = {}) {
// 만약 boundary가 주어지지 않았고 width와 height가 주어졌다면
// boundary를 width와 height로 설정한다.
if (typeof options.boundary !== "object") {
options.boundary = {};
}
if (typeof options.width === "number") {
options.boundary.width = typeCheck(
options.boundary.width,
"number",
options.width
);
}
if (typeof options.height === "number") {
options.boundary.height = typeCheck(
options.boundary.height,
"number",
options.height
);
}
super(options);
/**
* 사각형의 가로, 세로를 의미한다.
* 기본값은 50이다.
* width속성에 저장하지 않고 transform의 size에 저장한다.
*/
this.transform.setSize(
new Vector(
typeCheck(options.width, "number", 50),
typeCheck(options.height, "number", 50)
)
);
if (typeof options.boundary !== "object") {
options.boundary = new Object();
}
if (
typeof options.boundary.width !== "number" &&
typeof options.width === "number"
) {
options.boundary.width = typeCheck(options.width, "number", 0);
}
if (
typeof options.boundary.height !== "number" &&
typeof options.height === "number"
) {
options.boundary.height = typeCheck(options.height, "number", 0);
}
/**
* 윤곽선을 그릴 것인지를 의미한다.
* 윤곽선을 그리기 위해서는 옵션에서 strokeColor나
* strokeWidth를 설정하여야한다.
*
* @type {boolean}
*/
this.isStroke =
options.hasOwnProperty("strokeColor") ||
options.hasOwnProperty("strokeWidth");
if (this.isStroke) {
/**
* 윤곽선의 색상을 의미한다.
* 만약 옵션에서 윤곽선에 대한 정보가 있다면 isStroke는 true로 설정되고
* 윤곽선의 색상이 설정된다.
*
* @type {Color}
*/
this.strokeColor = typeCheck(
options.strokeColor,
Color,
new Color(
Math.random() * 255,
Math.random() * 255,
Math.random() * 255,
1
)
);
}
/**
* 윤곽선의 두께를 의미한다.
* 기본값은 1이다.
* 값의 범위는 1 ~ 15다.
*
* @type {number}
*/
this.setStrokeWidth(options.strokeWidth);
}
/**
* 화면에 사각형과 윤곽선을 그린다.
*/
draw() {
this.context2d.fillStyle = `rgb(
${this.color.r},
${this.color.g},
${this.color.b}
)`;
this.context2d.fillRect(
-this.getSize().x / 2,
-this.getSize().y / 2,
this.getSize().x,
this.getSize().y
);
// 윤곽선을 그리도록 설정했다면 윤곽선을 렌더링한다.
if (this.isStroke) {
this.context2d.lineWidth = this.strokeWidth;
this.context2d.strokeStyle = `rgb(
${this.strokeColor.r},
${this.strokeColor.g},
${this.strokeColor.b}
)`;
this.context2d.strokeRect(
this.strokeWidth / 2 - this.getSize().x / 2,
this.strokeWidth / 2 - this.getSize().y / 2,
this.getSize().x - this.strokeWidth,
this.getSize().y - this.strokeWidth
);
}
}
/**
* 윤곽선의 두께를 설정한다.
*
* @param {number} width - 윤곽선의 두께
*/
setStrokeWidth(width) {
this.strokeWidth = typeCheckAndClamp(width, "number", 1, 1, 15);
}
}
export default Rect;