mirror of
https://github.com/Aviortheking/games.git
synced 2025-04-23 19:32:09 +00:00
feat: Upgraded Engine
Signed-off-by: Avior <f.bouillon@aptatio.com>
This commit is contained in:
parent
bfd4beeaa4
commit
26df50c4a8
5
next-env.d.ts
vendored
5
next-env.d.ts
vendored
@ -1,2 +1,5 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
|
|
||||||
|
// NOTE: This file should not be edited
|
||||||
|
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||||
|
@ -19,5 +19,5 @@ module.exports = withPlugins([
|
|||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
],
|
],
|
||||||
nextConfig
|
//nextConfig
|
||||||
)
|
)
|
||||||
|
15075
package-lock.json
generated
15075
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
51
package.json
51
package.json
@ -10,32 +10,33 @@
|
|||||||
"test": "jest --config jext.config.js"
|
"test": "jest --config jext.config.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dzeio/components": "^0.10.1",
|
"@dzeio/components": "^1.0.0-beta.10",
|
||||||
"@dzeio/object-util": "^1.2.0",
|
"@dzeio/listener": "^1.0.3",
|
||||||
"critters": "^0.0.10",
|
"@dzeio/object-util": "^1",
|
||||||
"easy-sitemap": "^1.0.0",
|
"critters": "^0.0.16",
|
||||||
"next": "^11.0.0",
|
"easy-sitemap": "^1",
|
||||||
"next-compose-plugins": "^2.2.0",
|
"lucide-react": "^0.102.0",
|
||||||
"next-plausible": "^1.6.1",
|
"next": "^12",
|
||||||
"next-pre-css": "^1.0.0",
|
"next-compose-plugins": "^2",
|
||||||
"react": "^17.0.2",
|
"next-plausible": "^3",
|
||||||
"react-dom": "^17.0.2",
|
"next-pre-css": "https://github.com/tcgdex/next-pre-css.git",
|
||||||
"react-feather": "^2.0.9",
|
"react": "^18",
|
||||||
"stylus": "^0.54.7",
|
"react-dom": "^18",
|
||||||
"stylus-loader": "^6.0.0",
|
"stylus": "^0.59.0",
|
||||||
"typescript": "^4.1.3",
|
"stylus-loader": "^7",
|
||||||
"webpack": "^5.37.1"
|
"typescript": "^4",
|
||||||
|
"webpack": "^5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.8.7",
|
"@babel/core": "^7",
|
||||||
"@types/favicons": "^6.2.0",
|
"@types/favicons": "^6",
|
||||||
"@types/node": "^15.6.0",
|
"@types/node": "^18",
|
||||||
"@types/react": "^17.0.0",
|
"@types/react": "18.0.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.14.1",
|
"@typescript-eslint/eslint-plugin": "^5",
|
||||||
"@typescript-eslint/parser": "^4.14.1",
|
"@typescript-eslint/parser": "^5",
|
||||||
"eslint": "^7.1.0",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "^10.2.2",
|
"eslint-config-next": "^12",
|
||||||
"eslint-plugin-react": "^7.18.3",
|
"eslint-plugin-react": "^7",
|
||||||
"ts-node": "^9.1.1"
|
"ts-node": "^10"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
42
src/GameEngine/2D/Collider/BoxCollider2D.ts
Normal file
42
src/GameEngine/2D/Collider/BoxCollider2D.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import Collider from '.'
|
||||||
|
import Vector2D from '../Vector2D'
|
||||||
|
|
||||||
|
export default class BoxCollider2D extends Collider<{
|
||||||
|
center?: Vector2D
|
||||||
|
scale?: Vector2D
|
||||||
|
}> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns [Vector2D, Vector2D, Vector2D, Vector2D] the four points of the box collider
|
||||||
|
*/
|
||||||
|
public pos(): [Vector2D, Vector2D, Vector2D, Vector2D] {
|
||||||
|
const middle = this.component.getAbsolutePosition(false).sum(this.component.scale.x / 2, this.component.scale.y / 2)
|
||||||
|
const topLeft = this.applyRotation(this.component.getAbsolutePosition(false), middle, this.component.rotation)
|
||||||
|
const topRight = this.applyRotation(topLeft.sum(this.component.scale.x, 0), middle, this.component.rotation)
|
||||||
|
const bottomLeft = this.applyRotation(topLeft.sum(0, this.component.scale.y), middle, this.component.rotation)
|
||||||
|
const bottomRight = this.applyRotation(topLeft.sum(this.component.scale), middle, this.component.rotation)
|
||||||
|
|
||||||
|
return [
|
||||||
|
topLeft,
|
||||||
|
topRight,
|
||||||
|
bottomLeft,
|
||||||
|
bottomRight
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyRotation(point: Vector2D, middle: Vector2D, rotation: number) {
|
||||||
|
if (rotation === 0) {
|
||||||
|
return point.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Fix rotation not returning the correct points for points other than topleft
|
||||||
|
return point.clone()
|
||||||
|
const rot = rotation * (Math.PI / 180)
|
||||||
|
const tmp = point.clone().sum(-middle.x, -middle.y)
|
||||||
|
return new Vector2D(
|
||||||
|
middle.x + (tmp.x * Math.cos(rot) - tmp.y * Math.sin(rot)),
|
||||||
|
middle.y + (tmp.x * Math.sin(rot) + tmp.y * Math.cos(rot))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
105
src/GameEngine/2D/Collider/Checker.ts
Normal file
105
src/GameEngine/2D/Collider/Checker.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import Collider from '.'
|
||||||
|
import Vector2D from '../Vector2D'
|
||||||
|
import BoxCollider2D from './BoxCollider2D'
|
||||||
|
import Circlecollider2D from './CircleCollider2D'
|
||||||
|
import PointCollider2D from './PointCollider2D'
|
||||||
|
|
||||||
|
export default class Checker {
|
||||||
|
public static boxCircleCollision(box: BoxCollider2D, circle: Circlecollider2D): boolean {
|
||||||
|
// clamp(value, min, max) - limits value to the range min..max
|
||||||
|
|
||||||
|
// Find the closest point to the circle within the rectangle
|
||||||
|
const [topLeft, bottomRight] = box.pos()
|
||||||
|
const center = circle.center()
|
||||||
|
const radius = circle.radius()
|
||||||
|
const closestX = this.clamp(center.x, topLeft.x, bottomRight.x)
|
||||||
|
const closestY = this.clamp(center.y, topLeft.y, bottomRight.y)
|
||||||
|
|
||||||
|
// Calculate the distance between the circle's center and this closest point
|
||||||
|
const distanceX = center.x - closestX
|
||||||
|
const distanceY = center.y - closestY
|
||||||
|
|
||||||
|
// If the distance is less than the circle's radius, an intersection occurs
|
||||||
|
const distanceSquared = distanceX * distanceX + distanceY * distanceY
|
||||||
|
return distanceSquared < radius * radius
|
||||||
|
}
|
||||||
|
|
||||||
|
public static circleCircleCollision(circle1: Circlecollider2D, circle2: Circlecollider2D) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
public static pointBoxCollision(box1: PointCollider2D, box2: BoxCollider2D) {
|
||||||
|
const [topLeft, , , bottomRight] = box2.pos()
|
||||||
|
return box1.pos().isIn(topLeft, bottomRight)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dumb way to check currntly
|
||||||
|
*
|
||||||
|
* TODO: Handle rotation
|
||||||
|
*/
|
||||||
|
public static boxBoxCollision(box1: BoxCollider2D, box2: BoxCollider2D): boolean {
|
||||||
|
|
||||||
|
const selfPos = box1.pos()
|
||||||
|
const otherPos = box2.pos()
|
||||||
|
|
||||||
|
return selfPos[3].x >= otherPos[0].x && // self bottom higher than other top
|
||||||
|
selfPos[0].x <= otherPos[3].x &&
|
||||||
|
selfPos[3].y >= otherPos[0].y &&
|
||||||
|
selfPos[0].y <= otherPos[3].y
|
||||||
|
|
||||||
|
// const b1 = box1.pos()
|
||||||
|
// const b2 = box2.pos()
|
||||||
|
// for (const box1It of b1) {
|
||||||
|
// if (this.pointInRectangle(box1It, b2)) {
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line complexity
|
||||||
|
public static detectCollision(collider1: Collider, collider2: Collider, reverse = false): boolean {
|
||||||
|
if (collider1 instanceof BoxCollider2D && collider2 instanceof Circlecollider2D) {
|
||||||
|
return this.boxCircleCollision(collider1, collider2)
|
||||||
|
} else if (collider1 instanceof Circlecollider2D && collider2 instanceof Circlecollider2D) {
|
||||||
|
return this.circleCircleCollision(collider2, collider1)
|
||||||
|
} else if (collider1 instanceof BoxCollider2D && collider2 instanceof BoxCollider2D) {
|
||||||
|
return this.boxBoxCollision(collider2, collider1)
|
||||||
|
} else if (collider1 instanceof BoxCollider2D && collider2 instanceof PointCollider2D) {
|
||||||
|
return this.pointBoxCollision(collider2, collider1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reverse) {
|
||||||
|
return this.detectCollision(collider2, collider1, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private static clamp(value: number, min: number, max: number) {
|
||||||
|
return min > value ? min : max < value ? max : value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIXME: does not work perfecly
|
||||||
|
*
|
||||||
|
* @param point the point to check
|
||||||
|
* @param rectangle the rectangle in which to check
|
||||||
|
* @returns if the point is in the defined rectangle or not
|
||||||
|
*/
|
||||||
|
private static pointInRectangle(point: Vector2D, rectangle: [Vector2D, Vector2D, Vector2D, Vector2D]) {
|
||||||
|
const ab = rectangle[1].sum(-rectangle[0].x, -rectangle[0].y)
|
||||||
|
const ad = rectangle[3].sum(-rectangle[0].x, -rectangle[0].y)
|
||||||
|
const am = point.sum(-rectangle[0].x, -rectangle[0].y)
|
||||||
|
|
||||||
|
const abam = ab.x * am.x + ab.y * am.y
|
||||||
|
const abab = ab.x * ab.x + ab.y * ab.y
|
||||||
|
const amad = am.x * ad.x + am.y * ad.y
|
||||||
|
const adad = ad.x * ad.x + ad.y * ad.y
|
||||||
|
|
||||||
|
return 0 <= abam && abam <= abab &&
|
||||||
|
0 <= amad && amad <= adad
|
||||||
|
}
|
||||||
|
}
|
16
src/GameEngine/2D/Collider/CircleCollider2D.ts
Normal file
16
src/GameEngine/2D/Collider/CircleCollider2D.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import Collider from '.'
|
||||||
|
import Vector2D from '../Vector2D'
|
||||||
|
|
||||||
|
export default class Circlecollider2D extends Collider<{
|
||||||
|
radius?: number
|
||||||
|
offset?: Vector2D
|
||||||
|
}> {
|
||||||
|
|
||||||
|
public center(): Vector2D {
|
||||||
|
return new Vector2D(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
public radius(): number {
|
||||||
|
return this.params.radius ?? 0
|
||||||
|
}
|
||||||
|
}
|
16
src/GameEngine/2D/Collider/PointCollider2D.ts
Normal file
16
src/GameEngine/2D/Collider/PointCollider2D.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import Collider from '.'
|
||||||
|
import Vector2D from '../Vector2D'
|
||||||
|
|
||||||
|
export default class PointCollider2D extends Collider<{
|
||||||
|
center?: Vector2D
|
||||||
|
scale?: Vector2D
|
||||||
|
}> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns Vector2D the position of the point
|
||||||
|
*/
|
||||||
|
public pos(): Vector2D {
|
||||||
|
return this.component.getAbsolutePosition()
|
||||||
|
}
|
||||||
|
}
|
17
src/GameEngine/2D/Collider/index.ts
Normal file
17
src/GameEngine/2D/Collider/index.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import Component2D from 'GameEngine/Component2D'
|
||||||
|
|
||||||
|
export default abstract class Collider<
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
|
T extends {} | void = {} | void
|
||||||
|
> {
|
||||||
|
|
||||||
|
public component!: Component2D
|
||||||
|
|
||||||
|
protected params: T = {} as T
|
||||||
|
|
||||||
|
public constructor(it: T | void) {
|
||||||
|
if (it) {
|
||||||
|
this.params = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,58 +0,0 @@
|
|||||||
import GameEngine from 'GameEngine'
|
|
||||||
import Component2D from 'GameEngine/Component2D'
|
|
||||||
import Vector2D from '../Vector2D'
|
|
||||||
|
|
||||||
type BuiltinCollisionTypes = 'click' | 'pointerDown' | 'pointerUp'
|
|
||||||
|
|
||||||
export default class BoxCollider2D {
|
|
||||||
public constructor(
|
|
||||||
private component: Component2D,
|
|
||||||
public type: BuiltinCollisionTypes | string = 'collision',
|
|
||||||
private center = new Vector2D(0, 0),
|
|
||||||
private scale = new Vector2D(1, 1)
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public pointColliding(point: Vector2D, type: BuiltinCollisionTypes | string = 'collision'): boolean {
|
|
||||||
if (this.type !== type) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return point.isIn(
|
|
||||||
...this.pos()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
public pos(): [Vector2D, Vector2D] {
|
|
||||||
const scale = this.scale.multiply(this.component.scale)
|
|
||||||
const positionCenter = GameEngine.getGameEngine().currentScene?.position.sum(this.component.origin.sub(
|
|
||||||
new Vector2D(
|
|
||||||
this.component.position.x,
|
|
||||||
this.component.position.y
|
|
||||||
)
|
|
||||||
)) ?? this.component.origin.sub(
|
|
||||||
new Vector2D(
|
|
||||||
this.component.position.x,
|
|
||||||
this.component.position.y
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
const center = this.center.sum(positionCenter)
|
|
||||||
return [new Vector2D(
|
|
||||||
center.x,
|
|
||||||
center.y
|
|
||||||
),
|
|
||||||
new Vector2D(
|
|
||||||
center.x + scale.x,
|
|
||||||
center.y + scale.y
|
|
||||||
)]
|
|
||||||
}
|
|
||||||
|
|
||||||
public collideWith(collider: BoxCollider2D) {
|
|
||||||
const selfPos = this.pos()
|
|
||||||
const otherPos = collider.pos()
|
|
||||||
|
|
||||||
return selfPos[1].x >= otherPos[0].x && // self bottom higher than other top
|
|
||||||
selfPos[0].x <= otherPos[1].x &&
|
|
||||||
selfPos[1].y >= otherPos[0].y &&
|
|
||||||
selfPos[0].y <= otherPos[1].y
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +1,29 @@
|
|||||||
import Component2D, { ComponentState } from 'GameEngine/Component2D'
|
import Component2D, { ComponentState } from 'GameEngine/Component2D'
|
||||||
import RectRenderer from 'GameEngine/Renderer/RectRenderer'
|
import RectRenderer from 'GameEngine/Renderer/RectRenderer'
|
||||||
import BoxCollider2D from '../Collision/BoxCollider2D'
|
|
||||||
import Vector2D from '../Vector2D'
|
import Vector2D from '../Vector2D'
|
||||||
|
|
||||||
export default class ColliderDebugger extends Component2D {
|
export default class ColliderDebugger extends Component2D<{collision?: Array<string>}> {
|
||||||
|
|
||||||
public readonly name = 'ColliderDebugger'
|
public readonly name = 'ColliderDebugger'
|
||||||
public constructor(component: Component2D, collider: BoxCollider2D) {
|
|
||||||
super()
|
public renderer: RectRenderer = new RectRenderer(this, {stroke: 'transparent'})
|
||||||
this.collider = collider
|
|
||||||
const [topLeft, bottomRight] = collider.pos()
|
public init() {
|
||||||
const size = topLeft.sub(bottomRight)
|
if (!this.parent) {
|
||||||
this.position = topLeft
|
console.error('cant setup, no parent')
|
||||||
this.scale = size
|
return
|
||||||
this.origin = new Vector2D(-(this.scale.x / 2), -(this.scale.y / 2))
|
}
|
||||||
this.renderer = new RectRenderer(this, {stroke: 'black'})
|
this.collider = this.parent.collider
|
||||||
|
this.position = new Vector2D(0)
|
||||||
|
this.scale = this.parent.scale
|
||||||
|
this.origin = this.parent.origin
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(state: ComponentState) {
|
public update(state: ComponentState) {
|
||||||
if (state.isColliding) {
|
if (state.collideWith?.filter((it) => !this.params.collision ? true : this.params.collision.includes(it.name)).length ?? 0 > 1) {
|
||||||
(this.renderer as RectRenderer).material = 'rgba(0, 255, 0, .7)'
|
this.renderer.material = 'rgba(0, 255, 0, .7)'
|
||||||
} else {
|
} else {
|
||||||
(this.renderer as RectRenderer).material = undefined
|
this.renderer.material = undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,14 @@ export default class Vector2D {
|
|||||||
public y: number
|
public y: number
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
x: number,
|
x: number | [number, number],
|
||||||
y?: number
|
y?: number
|
||||||
) {
|
) {
|
||||||
|
if (typeof x === 'object') {
|
||||||
|
this.x = x[0]
|
||||||
|
this.y = x[1]
|
||||||
|
return
|
||||||
|
}
|
||||||
this.x = x
|
this.x = x
|
||||||
if (typeof y === 'number') {
|
if (typeof y === 'number') {
|
||||||
this.y = y
|
this.y = y
|
||||||
@ -16,6 +21,11 @@ export default class Vector2D {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return a new vector multiplied with the current one
|
||||||
|
* @param v vector
|
||||||
|
* @returns a new vector
|
||||||
|
*/
|
||||||
public multiply(v: Vector2D): Vector2D {
|
public multiply(v: Vector2D): Vector2D {
|
||||||
return new Vector2D(
|
return new Vector2D(
|
||||||
v.x * this.x,
|
v.x * this.x,
|
||||||
@ -23,6 +33,12 @@ export default class Vector2D {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return a new vector summed with the current one
|
||||||
|
* @param v vector or x to add
|
||||||
|
* @param y y to add
|
||||||
|
* @returns a new vector
|
||||||
|
*/
|
||||||
public sum(v: Vector2D | number, y?: number): Vector2D {
|
public sum(v: Vector2D | number, y?: number): Vector2D {
|
||||||
if (typeof v === 'number') {
|
if (typeof v === 'number') {
|
||||||
return new Vector2D(this.x + v, this.y + (y ?? v))
|
return new Vector2D(this.x + v, this.y + (y ?? v))
|
||||||
@ -109,4 +125,8 @@ export default class Vector2D {
|
|||||||
public equal(vector: Vector2D): boolean {
|
public equal(vector: Vector2D): boolean {
|
||||||
return vector.x === this.x && vector.y === this.y
|
return vector.x === this.x && vector.y === this.y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public toArray(): [number, number] {
|
||||||
|
return [this.x, this.y]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ export default class Asset {
|
|||||||
this.image = new Image()
|
this.image = new Image()
|
||||||
this.image.src = this.path
|
this.image.src = this.path
|
||||||
this.image.onload = () => {
|
this.image.onload = () => {
|
||||||
|
console.log('resource loaded', this.path, this.image.width, this.image.height)
|
||||||
this.isLoaded = true
|
this.isLoaded = true
|
||||||
this.status = AssetStatus.LOADED
|
this.status = AssetStatus.LOADED
|
||||||
res()
|
res()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import BoxCollider2D from './2D/Collision/BoxCollider2D'
|
import Collider from './2D/Collider'
|
||||||
import Vector2D from './2D/Vector2D'
|
import Vector2D from './2D/Vector2D'
|
||||||
import Renderer from './Renderer'
|
import Renderer from './Renderer'
|
||||||
import Scene from './Scene'
|
import Scene from './Scene'
|
||||||
@ -6,7 +6,7 @@ import Scene from './Scene'
|
|||||||
export interface ComponentState {
|
export interface ComponentState {
|
||||||
mouseHovering?: boolean
|
mouseHovering?: boolean
|
||||||
/**
|
/**
|
||||||
* is it is collinding return the type of collision
|
* is it is colliding return the type of Collider
|
||||||
*/
|
*/
|
||||||
isColliding?: string
|
isColliding?: string
|
||||||
collideWith?: Array<Component2D>
|
collideWith?: Array<Component2D>
|
||||||
@ -16,9 +16,10 @@ export interface ComponentState {
|
|||||||
|
|
||||||
export type StaticComponent<
|
export type StaticComponent<
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
T extends {} | void = {} | void
|
T extends {} | void = {} | void,
|
||||||
|
C extends Component2D<T> = Component2D<T>
|
||||||
> =
|
> =
|
||||||
new (params: T | undefined) => Component2D<T>
|
new (params: T | undefined) => C
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 2D Component
|
* 2D Component
|
||||||
@ -71,10 +72,10 @@ T extends {} | void = {} | void
|
|||||||
/**
|
/**
|
||||||
* Component collider for events
|
* Component collider for events
|
||||||
*
|
*
|
||||||
* @type {BoxCollider2D}
|
* @type {Collider}
|
||||||
* @memberof Component2D
|
* @memberof Component2D
|
||||||
*/
|
*/
|
||||||
public collider?: BoxCollider2D
|
public collider?: Collider
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parent component of self is any
|
* Parent component of self is any
|
||||||
@ -109,6 +110,11 @@ T extends {} | void = {} | void
|
|||||||
*/
|
*/
|
||||||
public debug?: boolean
|
public debug?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component rotation in Degrees
|
||||||
|
*/
|
||||||
|
public rotation = 0
|
||||||
|
|
||||||
protected params: T = {} as T
|
protected params: T = {} as T
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,7 +123,7 @@ T extends {} | void = {} | void
|
|||||||
*/
|
*/
|
||||||
public abstract readonly name: string
|
public abstract readonly name: string
|
||||||
|
|
||||||
public constructor(it: T) {
|
public constructor(it: T | void) {
|
||||||
if (it) {
|
if (it) {
|
||||||
this.params = it
|
this.params = it
|
||||||
}
|
}
|
||||||
@ -136,14 +142,33 @@ T extends {} | void = {} | void
|
|||||||
|
|
||||||
public destroy?(): Promise<void> | void
|
public destroy?(): Promise<void> | void
|
||||||
|
|
||||||
public getAbsolutePosition(): Vector2D {
|
public getAbsolutePosition(calculateRotation = true): Vector2D {
|
||||||
const realPosition = this.position.sum(
|
let pos = this.position.sum(
|
||||||
this.scale.multiply(this.origin)
|
this.scale.multiply(this.origin)
|
||||||
)
|
)
|
||||||
if (!this.parent) {
|
|
||||||
return realPosition
|
if (this.parent) {
|
||||||
|
pos = pos.sum(this.parent.getAbsolutePosition(calculateRotation))
|
||||||
}
|
}
|
||||||
return realPosition.sum(this.parent.getAbsolutePosition())
|
|
||||||
|
if (this.rotation && calculateRotation) {
|
||||||
|
const middle = pos.clone().sum(this.scale.x / 2, this.scale.y / 2)
|
||||||
|
const rot = this.rotation * (Math.PI / 180)
|
||||||
|
const tmp = pos.clone().sum(-middle.x, -middle.y)
|
||||||
|
return pos.set(
|
||||||
|
middle.x + (tmp.x * Math.cos(rot) - tmp.y * Math.sin(rot)),
|
||||||
|
middle.y + (tmp.x * Math.sin(rot) + tmp.y * Math.cos(rot))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAbsoluteRotation(): number {
|
||||||
|
if (this.parent) {
|
||||||
|
return this.parent.getAbsoluteRotation() + this.rotation
|
||||||
|
}
|
||||||
|
return this.rotation
|
||||||
}
|
}
|
||||||
|
|
||||||
public setState(key: keyof ComponentState, value: any): void {
|
public setState(key: keyof ComponentState, value: any): void {
|
||||||
@ -153,4 +178,8 @@ T extends {} | void = {} | void
|
|||||||
public updateParam(key: keyof T, value: any): void {
|
public updateParam(key: keyof T, value: any): void {
|
||||||
this.params[key] = value
|
this.params[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getParam(key: keyof T): any {
|
||||||
|
return this.params[key]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,27 @@ import Cursor from './Cursor'
|
|||||||
/**
|
/**
|
||||||
* Currently not working Camera implementation
|
* Currently not working Camera implementation
|
||||||
*/
|
*/
|
||||||
export default class Camera extends Component2D {
|
export default class Camera extends Component2D<{
|
||||||
|
position?: Vector2D
|
||||||
|
zoom?: number
|
||||||
|
}> {
|
||||||
public name = 'Camera'
|
public name = 'Camera'
|
||||||
public position: Vector2D = new Vector2D(0)
|
public position: Vector2D = new Vector2D(0)
|
||||||
|
|
||||||
public zoom = 1
|
public zoom = 1
|
||||||
|
|
||||||
|
public init(): void | Promise<void> {
|
||||||
|
if (this.params.position) {
|
||||||
|
this.position = this.params.position
|
||||||
|
}
|
||||||
|
if (this.params.zoom) {
|
||||||
|
this.setZoom(this.params.zoom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public update() {
|
public update() {
|
||||||
let needCursorUpdate = false
|
let needCursorUpdate = false
|
||||||
const scene = GameEngine.getGameEngine().currentScene
|
const scene = GameEngine.getGameEngine()?.currentScene
|
||||||
if (!scene) {
|
if (!scene) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -42,4 +54,14 @@ export default class Camera extends Component2D {
|
|||||||
public setZoom(value: number) {
|
public setZoom(value: number) {
|
||||||
this.zoom = value
|
this.zoom = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addToZoom(value: number, min?: number, max?: number) {
|
||||||
|
this.zoom += value
|
||||||
|
if (min && min > this.zoom) {
|
||||||
|
this.zoom = min
|
||||||
|
}
|
||||||
|
if (max && max < this.zoom) {
|
||||||
|
this.zoom = max
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
36
src/GameEngine/Components/ComponentRenderer.ts
Normal file
36
src/GameEngine/Components/ComponentRenderer.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import Vector2D from 'GameEngine/2D/Vector2D'
|
||||||
|
import Component2D from 'GameEngine/Component2D'
|
||||||
|
import Renderer from 'GameEngine/Renderer'
|
||||||
|
|
||||||
|
export default class ComponentRenderer extends Component2D<{
|
||||||
|
renderer?: Renderer
|
||||||
|
position?: Vector2D
|
||||||
|
scale?: Vector2D
|
||||||
|
name?: string
|
||||||
|
}> {
|
||||||
|
|
||||||
|
public name = 'ComponentRenderer'
|
||||||
|
|
||||||
|
public update(): void | Promise<void> {
|
||||||
|
if (this.params.renderer) {
|
||||||
|
this.renderer = this.params.renderer
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.params.name) {
|
||||||
|
this.name = this.params.name
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.params.position) {
|
||||||
|
this.position = this.params.position
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.params.scale) {
|
||||||
|
this.scale = this.params.scale
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateRenderer(key: string, value: any) {
|
||||||
|
(this.renderer as any)[key as any] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
import GameEngine from 'GameEngine'
|
import GameEngine from 'GameEngine'
|
||||||
import BoxCollider2D from 'GameEngine/2D/Collision/BoxCollider2D'
|
import PointCollider2D from 'GameEngine/2D/Collider/PointCollider2D'
|
||||||
import Vector2D from 'GameEngine/2D/Vector2D'
|
import Vector2D from 'GameEngine/2D/Vector2D'
|
||||||
import Component2D from 'GameEngine/Component2D'
|
import Component2D from 'GameEngine/Component2D'
|
||||||
import RectRenderer from 'GameEngine/Renderer/RectRenderer'
|
import RectRenderer from 'GameEngine/Renderer/RectRenderer'
|
||||||
|
import Camera from './Camera'
|
||||||
|
|
||||||
export default class Cursor extends Component2D<{
|
export default class Cursor extends Component2D<{
|
||||||
debug?: boolean
|
debug?: boolean
|
||||||
@ -28,7 +29,9 @@ export default class Cursor extends Component2D<{
|
|||||||
|
|
||||||
public scale: Vector2D = new Vector2D(1)
|
public scale: Vector2D = new Vector2D(1)
|
||||||
|
|
||||||
public collider: BoxCollider2D = new BoxCollider2D(this)
|
public collider: PointCollider2D = new PointCollider2D()
|
||||||
|
|
||||||
|
private touchZoom = 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* event handled down event
|
* event handled down event
|
||||||
@ -91,14 +94,35 @@ export default class Cursor extends Component2D<{
|
|||||||
this.onUp(ev)
|
this.onUp(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private onTouchMove = (ev: TouchEvent) => {
|
private onTouchMove = (ev: TouchEvent) => {
|
||||||
// console.log('onTouchMove')
|
// console.log('onTouchMove')
|
||||||
this.onMove(ev.touches.item(0) ?? undefined)
|
this.onMove(ev.touches.item(0) ?? undefined)
|
||||||
|
if (ev.touches.length >= 2) {
|
||||||
|
const cam = GameEngine.getGameEngine().currentScene?.getComponents().find((it) => it.name === 'Camera') as Camera | undefined
|
||||||
|
if (!cam) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const nv = Math.hypot(
|
||||||
|
ev.touches[0].pageX - ev.touches[1].pageX,
|
||||||
|
ev.touches[0].pageY - ev.touches[1].pageY
|
||||||
|
)
|
||||||
|
|
||||||
|
cam.addToZoom(-((this.touchZoom - nv) / 100), 1)
|
||||||
|
this.touchZoom = nv
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onTouchStart = (ev: TouchEvent) => {
|
private onTouchStart = (ev: TouchEvent) => {
|
||||||
// console.log('onTouchStart')
|
// console.log('onTouchStart')
|
||||||
this.onDown(ev.touches.item(0) ?? undefined)
|
this.onDown(ev.touches.item(0) ?? undefined)
|
||||||
|
if (ev.touches.length >= 2) {
|
||||||
|
this.touchZoom = Math.hypot(
|
||||||
|
ev.touches[0].pageX - ev.touches[1].pageX,
|
||||||
|
ev.touches[0].pageY - ev.touches[1].pageY
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onTouchEnd = (ev: TouchEvent) => {
|
private onTouchEnd = (ev: TouchEvent) => {
|
||||||
@ -122,7 +146,7 @@ export default class Cursor extends Component2D<{
|
|||||||
* Catch the onDown events
|
* Catch the onDown events
|
||||||
*/
|
*/
|
||||||
private onDown(ev?: MouseEvent | Touch) {
|
private onDown(ev?: MouseEvent | Touch) {
|
||||||
console.log('cursor down')
|
// console.log('cursor down')
|
||||||
if (ev) {
|
if (ev) {
|
||||||
this.updatePosition(
|
this.updatePosition(
|
||||||
ev.clientX ?? 0,
|
ev.clientX ?? 0,
|
||||||
@ -136,7 +160,7 @@ export default class Cursor extends Component2D<{
|
|||||||
* catch the onUp events
|
* catch the onUp events
|
||||||
*/
|
*/
|
||||||
private onUp(ev?: MouseEvent | Touch) {
|
private onUp(ev?: MouseEvent | Touch) {
|
||||||
console.log('cursor up')
|
// console.log('cursor up')
|
||||||
if (ev) {
|
if (ev) {
|
||||||
this.updatePosition(
|
this.updatePosition(
|
||||||
ev.clientX ?? 0,
|
ev.clientX ?? 0,
|
||||||
@ -146,8 +170,12 @@ export default class Cursor extends Component2D<{
|
|||||||
this.eventDown = false
|
this.eventDown = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line complexity
|
||||||
private updatePosition(clientX: number, clientY: number) {
|
private updatePosition(clientX: number, clientY: number) {
|
||||||
const ge = GameEngine.getGameEngine()
|
const ge = GameEngine.getGameEngine()
|
||||||
|
if (!ge) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.oldPosition = [clientX, clientY]
|
this.oldPosition = [clientX, clientY]
|
||||||
this.position.set(
|
this.position.set(
|
||||||
((clientX ?? 0) + window.scrollX - ge.canvas.offsetLeft) /
|
((clientX ?? 0) + window.scrollX - ge.canvas.offsetLeft) /
|
||||||
|
@ -7,6 +7,7 @@ import Renderer from '.'
|
|||||||
interface Params {
|
interface Params {
|
||||||
asset?: Asset
|
asset?: Asset
|
||||||
stream?: boolean
|
stream?: boolean
|
||||||
|
imageRotation?: number
|
||||||
debug?: boolean
|
debug?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,13 +18,15 @@ export default class ImageRenderer extends Renderer implements Params {
|
|||||||
|
|
||||||
public asset?: Asset
|
public asset?: Asset
|
||||||
public stream = true
|
public stream = true
|
||||||
|
public imageRotation = 0
|
||||||
public debug = false
|
public debug = false
|
||||||
|
|
||||||
public constructor(component: Component2D, params?: Params) {
|
public constructor(component: Component2D, params?: Params) {
|
||||||
super(component)
|
super(component)
|
||||||
objectLoop(params ?? {}, (value, key) => {this[key as keyof Params] = value})
|
objectLoop(params ?? {}, (value, key) => {this[key as 'stream'] = value as any})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line complexity
|
||||||
public async render(ge: GameEngine, ctx: CanvasRenderingContext2D) {
|
public async render(ge: GameEngine, ctx: CanvasRenderingContext2D) {
|
||||||
|
|
||||||
if (!this.asset) {
|
if (!this.asset) {
|
||||||
@ -44,15 +47,9 @@ export default class ImageRenderer extends Renderer implements Params {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const globalScale = ge.currentScene?.scale ?? 1
|
|
||||||
const size = this.asset.size()
|
const size = this.asset.size()
|
||||||
const position = this.getPosition()
|
const final = this.preRender(ctx, ge, this.imageRotation)
|
||||||
const final: [number, number, number, number] = [
|
|
||||||
position.x * ge.caseSize.x * globalScale,
|
|
||||||
position.y * ge.caseSize.y * globalScale,
|
|
||||||
(this.component.scale.x ?? ge.caseSize.x) * ge.caseSize.x * globalScale,
|
|
||||||
(this.component.scale.y ?? ge.caseSize.y) * ge.caseSize.y * globalScale
|
|
||||||
]
|
|
||||||
if (this.debug || this.component.debug) {
|
if (this.debug || this.component.debug) {
|
||||||
ctx.fillStyle = 'red'
|
ctx.fillStyle = 'red'
|
||||||
ctx.fillRect(...final)
|
ctx.fillRect(...final)
|
||||||
@ -65,5 +62,7 @@ export default class ImageRenderer extends Renderer implements Params {
|
|||||||
size.y,
|
size.y,
|
||||||
...final
|
...final
|
||||||
)
|
)
|
||||||
|
|
||||||
|
this.postRender(ctx, ge)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,22 +17,11 @@ export default class RectRenderer extends Renderer implements Params {
|
|||||||
|
|
||||||
public constructor(component: Component2D, params?: Params) {
|
public constructor(component: Component2D, params?: Params) {
|
||||||
super(component)
|
super(component)
|
||||||
objectLoop(params ?? {}, (value, key) => {this[key as 'material'] = value})
|
objectLoop(params ?? {}, (value, key) => {this[key] = value as any})
|
||||||
}
|
}
|
||||||
|
|
||||||
public async render(ge: GameEngine, ctx: CanvasRenderingContext2D) {
|
public async render(ge: GameEngine, ctx: CanvasRenderingContext2D) {
|
||||||
const position = this.getPosition()
|
const item = this.preRender(ctx, ge)
|
||||||
const globalScale = ge.currentScene?.scale ?? 1
|
|
||||||
const item: [number, number, number, number] = [
|
|
||||||
// source x
|
|
||||||
position.x * ge.caseSize.x * globalScale,
|
|
||||||
// source y
|
|
||||||
position.y * ge.caseSize.y * globalScale,
|
|
||||||
// size X
|
|
||||||
this.component.scale.x * ge.caseSize.x * globalScale,
|
|
||||||
// size Y
|
|
||||||
this.component.scale.y * ge.caseSize.y * globalScale
|
|
||||||
]
|
|
||||||
|
|
||||||
if (this.material) {
|
if (this.material) {
|
||||||
ctx.fillStyle = this.material
|
ctx.fillStyle = this.material
|
||||||
@ -57,5 +46,7 @@ export default class RectRenderer extends Renderer implements Params {
|
|||||||
}
|
}
|
||||||
ctx.strokeRect(...item)
|
ctx.strokeRect(...item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.postRender(ctx, ge)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,31 +23,30 @@ export default class TextRenderer extends Renderer implements Params {
|
|||||||
|
|
||||||
public constructor(component: Component2D, params?: Params) {
|
public constructor(component: Component2D, params?: Params) {
|
||||||
super(component)
|
super(component)
|
||||||
objectLoop(params ?? {}, (v, k) => {this[k as 'text'] = v})
|
objectLoop(params ?? {}, (value, key) => {this[key] = value as any})
|
||||||
}
|
}
|
||||||
|
|
||||||
public async render(ge: GameEngine, ctx: CanvasRenderingContext2D) {
|
public async render(ge: GameEngine, ctx: CanvasRenderingContext2D) {
|
||||||
const position = this.getPosition()
|
|
||||||
const globalScale = ge.currentScene?.scale ?? 1
|
const globalScale = ge.currentScene?.scale ?? 1
|
||||||
const item: [number, number] = [
|
const item = this.preRender(ctx, ge)
|
||||||
// source x
|
|
||||||
// 0 - 1.5 - -1.5
|
|
||||||
position.x * ge.caseSize.x * globalScale,
|
|
||||||
// source y
|
|
||||||
position.y * ge.caseSize.y * globalScale
|
|
||||||
]
|
|
||||||
|
|
||||||
const size = this.component.scale.y * ge.caseSize.y
|
const size = this.component.scale.y * ge.caseSize.y
|
||||||
|
|
||||||
// console.log
|
if (!this.text) {
|
||||||
if (this.text) {
|
if (this.debug) {
|
||||||
|
console.warn('no text, no display')
|
||||||
|
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx.textBaseline = 'top'
|
ctx.textBaseline = 'top'
|
||||||
ctx.textAlign = 'left'
|
ctx.textAlign = 'left'
|
||||||
|
|
||||||
ctx.font = `${this.weight ? `${this.weight} ` : ''}${(this.size ?? size) / 16 * ge.caseSize.x * globalScale * 3}px sans-serif`
|
ctx.font = `${this.weight ? `${this.weight} ` : ''}${(this.size ?? size) / 16 * ge.caseSize.x * globalScale * 3}px sans-serif`
|
||||||
if (this.color) {
|
if (this.color) {
|
||||||
ctx.fillStyle = this.color ?? 'black'
|
ctx.fillStyle = this.color ?? 'black'
|
||||||
ctx.fillText(this.text, ...item)
|
ctx.fillText(this.text, item[0], item[1])
|
||||||
}
|
}
|
||||||
if (this.stroke) {
|
if (this.stroke) {
|
||||||
if (typeof this.stroke === 'string') {
|
if (typeof this.stroke === 'string') {
|
||||||
@ -57,10 +56,9 @@ export default class TextRenderer extends Renderer implements Params {
|
|||||||
ctx.strokeStyle = this.stroke.color
|
ctx.strokeStyle = this.stroke.color
|
||||||
ctx.lineWidth = this.stroke.width * (ge.currentScene?.scale ?? 1)
|
ctx.lineWidth = this.stroke.width * (ge.currentScene?.scale ?? 1)
|
||||||
}
|
}
|
||||||
ctx.strokeText(this.text, ...item)
|
ctx.strokeText(this.text, item[0], item[1])
|
||||||
}
|
|
||||||
} else if (this.debug) {
|
|
||||||
console.warn('no text, no display')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.postRender(ctx, ge)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ export default class TileRenderer extends Renderer implements Params {
|
|||||||
|
|
||||||
public constructor(component: Component2D, params?: Params) {
|
public constructor(component: Component2D, params?: Params) {
|
||||||
super(component)
|
super(component)
|
||||||
objectLoop(params ?? {}, (value, key) => {this[key as 'id'] = value})
|
objectLoop(params ?? {}, (value, key) => {this[key] = value as any})
|
||||||
}
|
}
|
||||||
|
|
||||||
public async render(ge: GameEngine, ctx: CanvasRenderingContext2D) {
|
public async render(ge: GameEngine, ctx: CanvasRenderingContext2D) {
|
||||||
|
@ -8,9 +8,10 @@ export default abstract class Renderer {
|
|||||||
protected component: Component2D
|
protected component: Component2D
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
protected getPosition(): Vector2D {
|
protected getPosition(component?: Component2D): Vector2D {
|
||||||
|
|
||||||
const ge = GameEngine.getGameEngine()
|
const ge = GameEngine.getGameEngine()
|
||||||
const realPosition = this.component.getAbsolutePosition().sum(
|
const realPosition = (component ?? this.component).getAbsolutePosition().sum(
|
||||||
-(ge.currentScene?.position?.x ?? 0),
|
-(ge.currentScene?.position?.x ?? 0),
|
||||||
-(ge.currentScene?.position?.y ?? 0)
|
-(ge.currentScene?.position?.y ?? 0)
|
||||||
)
|
)
|
||||||
@ -18,5 +19,96 @@ export default abstract class Renderer {
|
|||||||
return realPosition
|
return realPosition
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected realPosition(ge: GameEngine): [number, number, number, number] {
|
||||||
|
const position = this.getPosition()
|
||||||
|
const globalScale = ge.currentScene?.scale ?? 1
|
||||||
|
return [
|
||||||
|
position.x * ge.caseSize.x * globalScale,
|
||||||
|
position.y * ge.caseSize.y * globalScale,
|
||||||
|
this.component.scale.x * ge.caseSize.x * globalScale,
|
||||||
|
this.component.scale.y * ge.caseSize.y * globalScale
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
protected selfPosition(ge: GameEngine): [number, number, number, number] {
|
||||||
|
const position = this.component.position
|
||||||
|
const globalScale = ge.currentScene?.scale ?? 1
|
||||||
|
return [
|
||||||
|
position.x * ge.caseSize.x * globalScale,
|
||||||
|
position.y * ge.caseSize.y * globalScale,
|
||||||
|
(this.component.scale.x ?? ge.caseSize.x) * ge.caseSize.x * globalScale,
|
||||||
|
(this.component.scale.y ?? ge.caseSize.y) * ge.caseSize.y * globalScale
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
protected parentRealPosition(ge: GameEngine): [number, number, number, number] {
|
||||||
|
const parent = this.component.parent
|
||||||
|
if (!parent) {
|
||||||
|
return [
|
||||||
|
0,0,0,0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
const position = this.getPosition(parent)
|
||||||
|
const globalScale = ge.currentScene?.scale ?? 1
|
||||||
|
return [
|
||||||
|
position.x * ge.caseSize.x * globalScale,
|
||||||
|
position.y * ge.caseSize.y * globalScale,
|
||||||
|
(parent.scale.x ?? ge.caseSize.x) * ge.caseSize.x * globalScale,
|
||||||
|
(this.component.scale.y ?? ge.caseSize.y) * ge.caseSize.y * globalScale
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate the component
|
||||||
|
*
|
||||||
|
* It needs to be closed by rotateFinish
|
||||||
|
* @param ctx the context
|
||||||
|
* @param rotation rotation in degrees
|
||||||
|
*/
|
||||||
|
protected rotateStart(ctx: CanvasRenderingContext2D, sizes: [number, number, number, number], rotation: number) {
|
||||||
|
const radians = rotation * Math.PI / 180
|
||||||
|
ctx.setTransform(
|
||||||
|
1, // Horizontal Scaling
|
||||||
|
0, // Horizontal Skewing
|
||||||
|
0, // Vertical Skewing
|
||||||
|
1, // Vertical Scaling
|
||||||
|
sizes[0], // Horizontal Moving
|
||||||
|
sizes[1] // Vertical Moving
|
||||||
|
)
|
||||||
|
ctx.rotate(radians)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected preRender(
|
||||||
|
ctx: CanvasRenderingContext2D,
|
||||||
|
ge: GameEngine,
|
||||||
|
additionnalRotation = 0
|
||||||
|
): [number, number, number, number] {
|
||||||
|
let position = this.realPosition(ge)
|
||||||
|
|
||||||
|
if (this.component.getAbsoluteRotation() !== 0 || additionnalRotation) {
|
||||||
|
this.rotateStart(
|
||||||
|
ctx,
|
||||||
|
this.component.parent ? this.parentRealPosition(ge) : position,
|
||||||
|
this.component.getAbsoluteRotation() + additionnalRotation
|
||||||
|
)
|
||||||
|
position = this.component.parent ? this.selfPosition(ge) : [0, 0, position[2], position[3]]
|
||||||
|
}
|
||||||
|
|
||||||
|
return position
|
||||||
|
}
|
||||||
|
|
||||||
|
protected postRender(ctx: CanvasRenderingContext2D, ge: GameEngine) {
|
||||||
|
|
||||||
|
// handle rotation reset
|
||||||
|
ctx.resetTransform()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ctx the context
|
||||||
|
*/
|
||||||
|
protected rotateFinish(ctx: CanvasRenderingContext2D) {
|
||||||
|
ctx.resetTransform()
|
||||||
|
}
|
||||||
|
|
||||||
public abstract render(ge: GameEngine, ctx: CanvasRenderingContext2D): Promise<void>
|
public abstract render(ge: GameEngine, ctx: CanvasRenderingContext2D): Promise<void>
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import GameEngine from 'GameEngine'
|
import GameEngine from 'GameEngine'
|
||||||
import Component2D, { ComponentState } from './Component2D'
|
import Collider from './2D/Collider'
|
||||||
import BoxCollider2D from './2D/Collision/BoxCollider2D'
|
import Checker from './2D/Collider/Checker'
|
||||||
import Vector2D from './2D/Vector2D'
|
import Vector2D from './2D/Vector2D'
|
||||||
import { ComponentType } from 'react'
|
import Component2D, { ComponentState } from './Component2D'
|
||||||
|
|
||||||
export default class Scene {
|
export default class Scene {
|
||||||
public static scenes: Record<string, Scene> = {}
|
public static scenes: Record<string, Scene> = {}
|
||||||
@ -12,8 +12,8 @@ export default class Scene {
|
|||||||
|
|
||||||
public position: Vector2D = new Vector2D(0)
|
public position: Vector2D = new Vector2D(0)
|
||||||
public scale = 1
|
public scale = 1
|
||||||
|
public components: Array<Component2D> = []
|
||||||
|
|
||||||
private components: Array<Component2D> = []
|
|
||||||
private componentsInitialized: Array<boolean> = []
|
private componentsInitialized: Array<boolean> = []
|
||||||
private ge!: GameEngine
|
private ge!: GameEngine
|
||||||
private hasClickedComponent: number | undefined
|
private hasClickedComponent: number | undefined
|
||||||
@ -86,15 +86,17 @@ export default class Scene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line complexity
|
||||||
public checkColisions(component: Component2D, exclusion?: Array<Component2D>): Array<Component2D> {
|
public checkColisions(component: Component2D, exclusion?: Array<Component2D>): Array<Component2D> {
|
||||||
const list: Array<Component2D> = []
|
const list: Array<Component2D> = []
|
||||||
if (component.collider instanceof BoxCollider2D) {
|
if (!component.collider) {
|
||||||
const [topLeft, bottomRight] = component.collider.pos()
|
return list
|
||||||
|
}
|
||||||
for (const otherComponent of this.components) {
|
for (const otherComponent of this.components) {
|
||||||
if (
|
if (
|
||||||
otherComponent === undefined ||
|
!otherComponent ||
|
||||||
otherComponent.id === component.id ||
|
otherComponent.id === component.id ||
|
||||||
!(otherComponent.collider instanceof BoxCollider2D)
|
!otherComponent.collider
|
||||||
) {
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -104,18 +106,21 @@ export default class Scene {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (component.collider) {
|
||||||
|
component.collider.component = component
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherComponent.collider) {
|
||||||
|
otherComponent.collider.component = otherComponent
|
||||||
|
}
|
||||||
|
|
||||||
// Check for collision
|
// Check for collision
|
||||||
const otherCollider = otherComponent.collider.pos()
|
|
||||||
if (
|
if (
|
||||||
bottomRight.x > otherCollider[0].x && // self bottom higher than other top
|
Checker.detectCollision(component.collider, otherComponent.collider)
|
||||||
topLeft.x < otherCollider[1].x &&
|
|
||||||
bottomRight.y > otherCollider[0].y &&
|
|
||||||
topLeft.y < otherCollider[1].y
|
|
||||||
) {
|
) {
|
||||||
list.push(otherComponent)
|
list.push(otherComponent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +135,7 @@ export default class Scene {
|
|||||||
|
|
||||||
if (component.childs) {
|
if (component.childs) {
|
||||||
for await (const child of component.childs) {
|
for await (const child of component.childs) {
|
||||||
|
child.parent = component
|
||||||
await this.initComponent(child)
|
await this.initComponent(child)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,7 +159,6 @@ export default class Scene {
|
|||||||
const toExclude: Array<Component2D> = []
|
const toExclude: Array<Component2D> = []
|
||||||
if (component.childs && component.childs.length > 0) {
|
if (component.childs && component.childs.length > 0) {
|
||||||
for await (const child of component.childs) {
|
for await (const child of component.childs) {
|
||||||
child.parent = component
|
|
||||||
toExclude.push(...await this.updateComponent(child))
|
toExclude.push(...await this.updateComponent(child))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ export default class GameEngine {
|
|||||||
/**
|
/**
|
||||||
* Maximum framerate you want to achieve
|
* Maximum framerate you want to achieve
|
||||||
*
|
*
|
||||||
* note: -1 mean infinite
|
* note: -1/undefined mean infinite
|
||||||
*/
|
*/
|
||||||
goalFramerate?: number
|
goalFramerate?: number
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import Tileset from 'GameEngine/Tileset'
|
|||||||
|
|
||||||
export class Explosion extends Component2D {
|
export class Explosion extends Component2D {
|
||||||
|
|
||||||
|
public name = 'Explosion'
|
||||||
public size = {
|
public size = {
|
||||||
width: .9,
|
width: .9,
|
||||||
height: .9
|
height: .9
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import GameEngine from 'GameEngine'
|
import GameEngine from 'GameEngine'
|
||||||
import BoxCollider2D from 'GameEngine/2D/Collision/BoxCollider2D'
|
import BoxCollider2D from 'GameEngine/2D/Collider/BoxCollider2D'
|
||||||
import ColliderDebugger from 'GameEngine/2D/Debug/ColliderDebugger'
|
import ColliderDebugger from 'GameEngine/2D/Debug/ColliderDebugger'
|
||||||
import PointDebugger from 'GameEngine/2D/Debug/PointDebugger'
|
import PointDebugger from 'GameEngine/2D/Debug/PointDebugger'
|
||||||
import Vector2D from 'GameEngine/2D/Vector2D'
|
import Vector2D from 'GameEngine/2D/Vector2D'
|
||||||
@ -16,7 +16,9 @@ export default class Item extends Component2D {
|
|||||||
|
|
||||||
public static explosion = new Explosion()
|
public static explosion = new Explosion()
|
||||||
|
|
||||||
public collider: BoxCollider2D = new BoxCollider2D(this, 'click')
|
public name = 'Item'
|
||||||
|
|
||||||
|
public collider: BoxCollider2D = new BoxCollider2D()
|
||||||
|
|
||||||
private x: number
|
private x: number
|
||||||
private y: number
|
private y: number
|
||||||
@ -43,7 +45,7 @@ export default class Item extends Component2D {
|
|||||||
// console.log(this.tileset.getSourceData(0), this.tileset.width(0), this.tileset.height(0))
|
// console.log(this.tileset.getSourceData(0), this.tileset.width(0), this.tileset.height(0))
|
||||||
// console.log(this.tileset.getSourceData(1))
|
// console.log(this.tileset.getSourceData(1))
|
||||||
this.childs = [
|
this.childs = [
|
||||||
new ColliderDebugger(this, this.collider),
|
new ColliderDebugger(),
|
||||||
new PointDebugger(this.collider.pos()[0]),
|
new PointDebugger(this.collider.pos()[0]),
|
||||||
new PointDebugger(this.collider.pos()[1])
|
new PointDebugger(this.collider.pos()[1])
|
||||||
]
|
]
|
||||||
|
@ -5,6 +5,7 @@ import RectRenderer from 'GameEngine/Renderer/RectRenderer'
|
|||||||
export default class Line extends Component2D {
|
export default class Line extends Component2D {
|
||||||
|
|
||||||
// public debug = true
|
// public debug = true
|
||||||
|
public name = 'Line'
|
||||||
|
|
||||||
public constructor(direction: number, index: number) {
|
public constructor(direction: number, index: number) {
|
||||||
super()
|
super()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import GameEngine from 'GameEngine'
|
import GameEngine from 'GameEngine'
|
||||||
import BoxCollider2D from 'GameEngine/2D/Collision/BoxCollider2D'
|
import BoxCollider2D from 'GameEngine/2D/Collider/BoxCollider2D'
|
||||||
import ColliderDebugger from 'GameEngine/2D/Debug/ColliderDebugger'
|
import ColliderDebugger from 'GameEngine/2D/Debug/ColliderDebugger'
|
||||||
import Vector2D from 'GameEngine/2D/Vector2D'
|
import Vector2D from 'GameEngine/2D/Vector2D'
|
||||||
import Component2D, { ComponentState } from 'GameEngine/Component2D'
|
import Component2D, { ComponentState } from 'GameEngine/Component2D'
|
||||||
@ -7,14 +7,15 @@ import RectRenderer from 'GameEngine/Renderer/RectRenderer'
|
|||||||
import { globalState } from '..'
|
import { globalState } from '..'
|
||||||
|
|
||||||
export default class Start extends Component2D {
|
export default class Start extends Component2D {
|
||||||
|
public name = 'Start'
|
||||||
public renderer: RectRenderer = new RectRenderer(this, {material: 'yellow'})
|
public renderer: RectRenderer = new RectRenderer(this, {material: 'yellow'})
|
||||||
public position: Vector2D = new Vector2D(1, 1)
|
public position: Vector2D = new Vector2D(1, 1)
|
||||||
public scale: Vector2D = new Vector2D(2, 1)
|
public scale: Vector2D = new Vector2D(2, 1)
|
||||||
public collider: BoxCollider2D = new BoxCollider2D(this, 'click')
|
public collider: BoxCollider2D = new BoxCollider2D()
|
||||||
public childs: Array<Component2D> = [new ColliderDebugger(this, this.collider)]
|
public childs: Array<Component2D> = [new ColliderDebugger()]
|
||||||
|
|
||||||
public update(state: ComponentState) {
|
public update(state: ComponentState) {
|
||||||
if (state.isColliding === 'click') {
|
if (state.collideWith?.find((it) => it.name === 'Cursor')) {
|
||||||
console.log('Start Game !')
|
console.log('Start Game !')
|
||||||
GameEngine.getGameEngine().setScene('TicTacToe')
|
GameEngine.getGameEngine().setScene('TicTacToe')
|
||||||
globalState.isPlaying = true
|
globalState.isPlaying = true
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React from 'react'
|
|
||||||
import App from 'next/app'
|
import App from 'next/app'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
import PlausibleProvider from 'next-plausible'
|
|
||||||
import '@dzeio/components/style.css'
|
import '@dzeio/components/style.css'
|
||||||
|
import PlausibleProvider from 'next-plausible'
|
||||||
|
|
||||||
export default class CApp extends App {
|
export default class CApp extends App {
|
||||||
|
|
||||||
@ -10,14 +10,14 @@ export default class CApp extends App {
|
|||||||
const { Component, pageProps } = this.props
|
const { Component, pageProps } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PlausibleProvider
|
// <PlausibleProvider
|
||||||
enabled
|
// enabled
|
||||||
customDomain="https://proxy.dzeio.com"
|
// customDomain="https://proxy.dzeio.com"
|
||||||
domain="games.avior.me"
|
// domain="games.avior.me"
|
||||||
integrity="sha256-R6vN8jmBq9SIpnfJRnw9eNUfLbC2yO3GPQAKR5ZS7zQ="
|
// integrity="sha256-R6vN8jmBq9SIpnfJRnw9eNUfLbC2yO3GPQAKR5ZS7zQ="
|
||||||
>
|
// >
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
</PlausibleProvider>
|
// </PlausibleProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Button, Text, Util, NotificationManager, Col, Row, Input } from '@dzeio/components'
|
import { Button, Col, Input, NotificationManager, Row, Text, Util } from '@dzeio/components'
|
||||||
import { GetServerSideProps } from 'next'
|
import { GetServerSideProps } from 'next'
|
||||||
import React, { MouseEvent as ReactMouseEvent } from 'react'
|
import React, { MouseEvent as ReactMouseEvent } from 'react'
|
||||||
import css from './pokemon-shuffle.module.styl'
|
import css from './pokemon-shuffle.module.styl'
|
||||||
@ -187,8 +187,9 @@ export default class PokemonShuffle extends React.Component<Props, States> {
|
|||||||
return NotificationManager.addNotification('Cant move nothing')
|
return NotificationManager.addNotification('Cant move nothing')
|
||||||
}
|
}
|
||||||
document.addEventListener('mousemove', this.mouveMove)
|
document.addEventListener('mousemove', this.mouveMove)
|
||||||
this.setState({movingItem: {x,y,cell}})
|
const items = this.state.items
|
||||||
this.state.items[y][x] = undefined
|
items[y][x] = undefined
|
||||||
|
this.setState({movingItem: {x,y,cell}, items})
|
||||||
this.mouveMove(ev.nativeEvent)
|
this.mouveMove(ev.nativeEvent)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
@ -6,9 +6,12 @@ import Scene from 'GameEngine/Scene'
|
|||||||
import Item from 'games/tictactoe/Item'
|
import Item from 'games/tictactoe/Item'
|
||||||
import Line from 'games/tictactoe/Line'
|
import Line from 'games/tictactoe/Line'
|
||||||
import Start from 'games/tictactoe/Menu/Start'
|
import Start from 'games/tictactoe/Menu/Start'
|
||||||
|
import Cursor from 'GameEngine/Components/Cursor'
|
||||||
|
|
||||||
export default class Snake extends React.PureComponent {
|
export default class Snake extends React.PureComponent {
|
||||||
|
|
||||||
|
private cursor = new Cursor()
|
||||||
|
|
||||||
public async componentDidMount() {
|
public async componentDidMount() {
|
||||||
const ge = new GameEngine('#test', {
|
const ge = new GameEngine('#test', {
|
||||||
caseCount: 3,
|
caseCount: 3,
|
||||||
@ -17,19 +20,21 @@ export default class Snake extends React.PureComponent {
|
|||||||
})
|
})
|
||||||
const menuScene = new Scene('Menu')
|
const menuScene = new Scene('Menu')
|
||||||
menuScene.addComponent(
|
menuScene.addComponent(
|
||||||
new Start()
|
new Start(),
|
||||||
|
this.cursor
|
||||||
)
|
)
|
||||||
const scene = new Scene('TicTacToe')
|
const scene = new Scene('TicTacToe')
|
||||||
scene.addComponent(
|
scene.addComponent(
|
||||||
...Array.from(new Array(2)).map((_, index) => new Line(0, index)),
|
...Array.from(new Array(2)).map((_, index) => new Line(0, index)),
|
||||||
...Array.from(new Array(2)).map((_, index) => new Line(1, index)),
|
...Array.from(new Array(2)).map((_, index) => new Line(1, index)),
|
||||||
...Array.from(new Array(9)).map((_, index) => new Item(index)),
|
...Array.from(new Array(9)).map((_, index) => new Item(index)),
|
||||||
Item.explosion
|
Item.explosion,
|
||||||
|
this.cursor
|
||||||
// new TilingDebugger()
|
// new TilingDebugger()
|
||||||
)
|
)
|
||||||
|
|
||||||
ge.start()
|
ge.setScene(menuScene).then(() => ge.start())
|
||||||
ge.setScene(menuScene)
|
// ge.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
public render = () => (
|
public render = () => (
|
||||||
|
@ -19,10 +19,17 @@
|
|||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"baseUrl": "./src",
|
"baseUrl": "./src",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@styl/*": ["client/styl/*"],
|
"@styl/*": [
|
||||||
"@cp/*": ["client/components/*"],
|
"client/styl/*"
|
||||||
"@smd/*": ["client/styl/modules/*"],
|
],
|
||||||
}
|
"@cp/*": [
|
||||||
|
"client/components/*"
|
||||||
|
],
|
||||||
|
"@smd/*": [
|
||||||
|
"client/styl/modules/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"incremental": true
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user