mirror of
https://github.com/Aviortheking/games.git
synced 2025-07-03 14:49:18 +00:00
@ -1,7 +1,7 @@
|
||||
import Component2D from 'GameEngine/Component2D'
|
||||
import Vector2D from '../Vector2D'
|
||||
|
||||
type BuiltinCollisionTypes = 'click'
|
||||
type BuiltinCollisionTypes = 'click' | 'pointerDown' | 'pointerUp'
|
||||
|
||||
export default class BoxCollider2D {
|
||||
public constructor(
|
||||
|
@ -1,14 +1,20 @@
|
||||
import Component2D from 'GameEngine/Component2D'
|
||||
import RectRenderer from 'GameEngine/Renderer/RectRenderer'
|
||||
import Vector2D from '../Vector2D'
|
||||
import PointDebugger from './PointDebugger'
|
||||
|
||||
export default class ComponentDebug extends Component2D {
|
||||
public constructor(component: Component2D) {
|
||||
super()
|
||||
this.position = component.position
|
||||
this.origin = component.origin
|
||||
this.scale = new Vector2D(.1, .1)
|
||||
this.position = new Vector2D(0, 0)
|
||||
// this.origin = component.origin
|
||||
this.scale = component.scale
|
||||
console.log('Position of the origin point', this.position)
|
||||
this.renderer = new RectRenderer(this, {material: 'red'})
|
||||
// this.renderer = new RectRenderer(this, {material: 'red'})
|
||||
this.childs = [
|
||||
new PointDebugger(new Vector2D(0, 0), 'aqua'),
|
||||
new PointDebugger(this.origin, 'green'),
|
||||
new PointDebugger(component.position.sum(component.scale), 'aqua')
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,12 @@ import RectRenderer from 'GameEngine/Renderer/RectRenderer'
|
||||
import Vector2D from '../Vector2D'
|
||||
|
||||
export default class PointDebugger extends Component2D {
|
||||
public constructor(point: Vector2D) {
|
||||
public constructor(point: Vector2D, color = 'red') {
|
||||
super()
|
||||
this.scale = new Vector2D(.1, .1)
|
||||
this.position = point
|
||||
console.log('Debugging point at location', point)
|
||||
// this.origin = component.origin
|
||||
this.renderer = new RectRenderer(this, {material: 'red'})
|
||||
this.renderer = new RectRenderer(this, {material: color})
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
export default class Size2D {
|
||||
private _width: number
|
||||
private _height?: number
|
||||
|
||||
public constructor(
|
||||
width: number,
|
||||
height?: number
|
||||
) {
|
||||
this._width = width
|
||||
this._height = height
|
||||
}
|
||||
|
||||
public get width() {
|
||||
return this._width
|
||||
}
|
||||
|
||||
public set width(v: number) {
|
||||
this._width = v
|
||||
}
|
||||
|
||||
|
||||
public get height() {
|
||||
return this._height ?? this._width
|
||||
}
|
||||
|
||||
public set height(v: number) {
|
||||
this._height = v
|
||||
}
|
||||
}
|
@ -4,7 +4,6 @@ export default class Vector2D {
|
||||
public y: number
|
||||
) {}
|
||||
|
||||
|
||||
public multiply(v: Vector2D): Vector2D {
|
||||
return new Vector2D(
|
||||
v.x * this.x,
|
||||
|
@ -1,3 +1,6 @@
|
||||
/**
|
||||
* Asset management Class
|
||||
*/
|
||||
export default class Asset {
|
||||
|
||||
public static assets: Record<string, Asset> = {}
|
||||
|
@ -1,5 +0,0 @@
|
||||
import Vector2D from './2D/Vector2D'
|
||||
|
||||
export default class Camera {
|
||||
public topLeft = new Vector2D(0.5, 0.5)
|
||||
}
|
@ -10,14 +10,45 @@ export interface ComponentState {
|
||||
isColliding?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 2D Component
|
||||
*/
|
||||
export default abstract class Component2D {
|
||||
|
||||
/**
|
||||
* Indicate how the component is rendered
|
||||
*
|
||||
* @type {Renderer}
|
||||
* @memberof Component2D
|
||||
*/
|
||||
public renderer?: Renderer
|
||||
|
||||
/**
|
||||
* Component position relative to the parent position and to the component origin
|
||||
*
|
||||
* (see also: Component2D.origin)
|
||||
*
|
||||
* @type {Vector2D}
|
||||
* @memberof Component2D
|
||||
*/
|
||||
public position: Vector2D = new Vector2D(0, 0)
|
||||
|
||||
/**
|
||||
* Component scale relative to 1 case size
|
||||
*
|
||||
* (see also: GameEngine.caseSize)
|
||||
*
|
||||
* @type {Vector2D}
|
||||
* @memberof Component2D
|
||||
*/
|
||||
public scale: Vector2D = new Vector2D(1, 1)
|
||||
|
||||
/**
|
||||
* Component collider for events
|
||||
*
|
||||
* @type {BoxCollider2D}
|
||||
* @memberof Component2D
|
||||
*/
|
||||
public collider?: BoxCollider2D
|
||||
|
||||
/**
|
||||
@ -25,11 +56,35 @@ export default abstract class Component2D {
|
||||
*/
|
||||
public origin: Vector2D = new Vector2D(0 , 0)
|
||||
|
||||
/**
|
||||
* Component Child Components
|
||||
*
|
||||
* @type {Array<Component2D>}
|
||||
* @memberof Component2D
|
||||
*/
|
||||
public childs: Array<Component2D> = []
|
||||
|
||||
/**
|
||||
* Component in debug mode
|
||||
* It will display more informations depending on the Collider and other items
|
||||
*
|
||||
* note: Does not apply to childs components
|
||||
*
|
||||
* @type {boolean}
|
||||
* @memberof Component2D
|
||||
*/
|
||||
public debug?: boolean
|
||||
|
||||
/**
|
||||
* Function run when the component is initialized
|
||||
*/
|
||||
public init?(): Promise<void> | void
|
||||
|
||||
/**
|
||||
* Function run on each game ticks
|
||||
* @param state the component state
|
||||
*/
|
||||
public update?(state: ComponentState): Promise<void> | void
|
||||
|
||||
public destroy?(): Promise<void> | void
|
||||
}
|
||||
|
8
src/GameEngine/Components/Camera.ts
Normal file
8
src/GameEngine/Components/Camera.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import Vector2D from '../2D/Vector2D'
|
||||
|
||||
/**
|
||||
* Currently not working Camera implementation
|
||||
*/
|
||||
export default class Camera {
|
||||
public topLeft = new Vector2D(0.5, 0.5)
|
||||
}
|
25
src/GameEngine/Components/FPSCounter.ts
Normal file
25
src/GameEngine/Components/FPSCounter.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import ComponentDebug from 'GameEngine/2D/Debug/ComponentDebug'
|
||||
import Vector2D from 'GameEngine/2D/Vector2D'
|
||||
import Component2D from 'GameEngine/Component2D'
|
||||
import Renderer from 'GameEngine/Renderer'
|
||||
import TextRenderer from 'GameEngine/Renderer/TextRenderer'
|
||||
|
||||
export default class FPSCounter extends Component2D {
|
||||
|
||||
|
||||
public position: Vector2D = new Vector2D(0,0)
|
||||
public scale: Vector2D = new Vector2D(1, 1)
|
||||
public origin: Vector2D = new Vector2D(0, 0)
|
||||
public childs: Array<Component2D> = [new ComponentDebug(this)]
|
||||
|
||||
public renderer: TextRenderer = new TextRenderer(this, {text: 'pouet'})
|
||||
|
||||
private lastUpdate: number = new Date().getTime()
|
||||
|
||||
public update() {
|
||||
const now = new Date().getTime()
|
||||
this.renderer.text = (1000 / (now - this.lastUpdate)).toFixed(2)
|
||||
this.lastUpdate = now
|
||||
}
|
||||
|
||||
}
|
31
src/GameEngine/Event/PointerEvents.ts
Normal file
31
src/GameEngine/Event/PointerEvents.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import Event from '.'
|
||||
|
||||
export default class PointerEvents extends Event {
|
||||
public override init(): void {
|
||||
document.addEventListener('mousemove', this.basicEvent)
|
||||
document.addEventListener('mousedown', this.mouseDown)
|
||||
document.addEventListener('mouseup', this.mouseUp)
|
||||
}
|
||||
|
||||
public update() {
|
||||
// pouet
|
||||
}
|
||||
|
||||
public override destroy() {
|
||||
document.removeEventListener('mousemove', this.basicEvent)
|
||||
document.removeEventListener('mousedown', this.mouseDown)
|
||||
document.removeEventListener('mouseup', this.mouseUp)
|
||||
}
|
||||
|
||||
private basicEvent = (ev: MouseEvent) => {
|
||||
console.log('Mouse Event :D')
|
||||
}
|
||||
|
||||
private mouseUp = (ev: MouseEvent) => {
|
||||
this.basicEvent(ev)
|
||||
}
|
||||
|
||||
private mouseDown = (ev: MouseEvent) => {
|
||||
this.basicEvent(ev)
|
||||
}
|
||||
}
|
11
src/GameEngine/Event/index.ts
Normal file
11
src/GameEngine/Event/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import GameEngine from 'GameEngine'
|
||||
|
||||
export default abstract class Event {
|
||||
public constructor(
|
||||
protected ge: GameEngine
|
||||
) {}
|
||||
|
||||
abstract init(): void
|
||||
abstract update(): void
|
||||
abstract destroy(): void
|
||||
}
|
@ -9,7 +9,7 @@ interface Params {
|
||||
stroke?: string
|
||||
}
|
||||
|
||||
export default class RectRenderer extends Renderer implements Partial<Params> {
|
||||
export default class RectRenderer extends Renderer implements Params {
|
||||
|
||||
public material?: string | Asset
|
||||
public stroke?: string
|
||||
|
41
src/GameEngine/Renderer/TextRenderer.ts
Normal file
41
src/GameEngine/Renderer/TextRenderer.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { objectLoop } from '@dzeio/object-util'
|
||||
import GameEngine from 'GameEngine'
|
||||
import Component2D from 'GameEngine/Component2D'
|
||||
import Renderer from '.'
|
||||
|
||||
interface Params {
|
||||
text?: string
|
||||
}
|
||||
|
||||
export default class TextRenderer extends Renderer {
|
||||
|
||||
public text?: string
|
||||
public size?: number
|
||||
|
||||
public constructor(component: Component2D, params?: Params) {
|
||||
super(component)
|
||||
objectLoop(params ?? {}, (v, k) => {this[k as 'text'] = v})
|
||||
}
|
||||
|
||||
public async render(ge: GameEngine, ctx: CanvasRenderingContext2D) {
|
||||
const position = this.getPosition()
|
||||
const item: [number, number] = [
|
||||
// source x
|
||||
// 0 - 1.5 - -1.5
|
||||
position.x * (ge.caseSize.x),
|
||||
// source y
|
||||
position.y * (ge.caseSize.y)
|
||||
]
|
||||
|
||||
const size = this.component.scale.y * ge.caseSize.y
|
||||
|
||||
// console.log
|
||||
if (this.text) {
|
||||
ctx.fillStyle = 'black'
|
||||
ctx.textBaseline = 'top'
|
||||
|
||||
ctx.font = `${size}px sans-serif`
|
||||
ctx.fillText(this.text, ...item)
|
||||
}
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ export default abstract class Renderer {
|
||||
|
||||
protected getPosition(): Vector2D {
|
||||
const ge = GameEngine.getGameEngine()
|
||||
const realPosition = ge.currentScene.camera.topLeft.sum(this.component.position)
|
||||
const realPosition = ge.currentScene!.camera.topLeft.sum(this.component.position)
|
||||
return new Vector2D(
|
||||
realPosition.x - this.component.scale.x / 2 - this.component.origin.x,
|
||||
realPosition.y - this.component.scale.y / 2 - this.component.origin.y
|
||||
|
@ -1,6 +1,6 @@
|
||||
import GameEngine from 'GameEngine'
|
||||
import AssetsManager from './Asset'
|
||||
import Camera from './Camera'
|
||||
import Camera from './Components/Camera'
|
||||
import Component2D, { ComponentState } from './Component2D'
|
||||
|
||||
export default class Scene {
|
||||
@ -42,6 +42,12 @@ export default class Scene {
|
||||
}
|
||||
}
|
||||
|
||||
public async destroy() {
|
||||
for await (const component of this.components) {
|
||||
await component.destroy?.()
|
||||
}
|
||||
}
|
||||
|
||||
private async updateComponent(v: Component2D) {
|
||||
const debug = v.debug
|
||||
if (debug) {
|
||||
@ -64,6 +70,13 @@ export default class Scene {
|
||||
// state.mouseClicking = state.mouseHovering && this.ge.cursor.isDown
|
||||
// state.mouseClicked = state.mouseClicking && !this.ge.cursor.wasDown
|
||||
// }
|
||||
if (v.update) {
|
||||
if (debug) {
|
||||
console.log('Updating Component', v)
|
||||
}
|
||||
v.update(state as ComponentState)
|
||||
}
|
||||
|
||||
if (v.renderer) {
|
||||
if (debug) {
|
||||
console.log('Rendering Component', v)
|
||||
@ -71,17 +84,12 @@ export default class Scene {
|
||||
// console.log('is rendering new element')
|
||||
await v.renderer.render(this.ge, this.ge.ctx)
|
||||
}
|
||||
if (v.update) {
|
||||
if (debug) {
|
||||
console.log('Updating Component', v)
|
||||
}
|
||||
v.update(state as ComponentState)
|
||||
}
|
||||
|
||||
if (v.childs) {
|
||||
if (debug) {
|
||||
console.log('Processing childs', v)
|
||||
}
|
||||
for (const child of v.childs) {
|
||||
for await (const child of v.childs) {
|
||||
await this.updateComponent(child)
|
||||
}
|
||||
}
|
||||
|
@ -21,15 +21,22 @@ export default class GameEngine {
|
||||
isDown: false,
|
||||
wasDown: false
|
||||
}
|
||||
public currentScene!: Scene
|
||||
public currentScene?: Scene
|
||||
private isRunning = false
|
||||
private timer = 16.6
|
||||
|
||||
public constructor(
|
||||
private id: string,
|
||||
id: string,
|
||||
public options?: {
|
||||
caseCount?: number | [number, number]
|
||||
background?: string
|
||||
debugColliders?: boolean
|
||||
/**
|
||||
* Maximum framerate you want to achieve
|
||||
*
|
||||
* note: -1 mean infinite
|
||||
*/
|
||||
goalFramerate?: number
|
||||
}
|
||||
) {
|
||||
GameEngine.ge = this
|
||||
@ -53,6 +60,14 @@ export default class GameEngine {
|
||||
}
|
||||
ctx.imageSmoothingEnabled = false
|
||||
this.ctx = ctx
|
||||
|
||||
if (options?.goalFramerate) {
|
||||
if (options.goalFramerate === -1) {
|
||||
this.timer = 0
|
||||
} else {
|
||||
this.timer = 1000 / options.goalFramerate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static getGameEngine(): GameEngine {
|
||||
@ -70,8 +85,8 @@ export default class GameEngine {
|
||||
})
|
||||
document.addEventListener('mousemove', (ev) => {
|
||||
this.cursor.position = new Vector2D(
|
||||
ev.clientX / this.caseSize.x - this.currentScene.camera.topLeft.x,
|
||||
ev.clientY / this.caseSize.y - this.currentScene.camera.topLeft.y
|
||||
ev.clientX / this.caseSize.x - (this.currentScene?.camera?.topLeft?.x ?? 0),
|
||||
ev.clientY / this.caseSize.y - (this.currentScene?.camera?.topLeft?.y ?? 0)
|
||||
)
|
||||
if (this.cursor.isDown) {
|
||||
this.cursor.wasDown = true
|
||||
@ -90,13 +105,15 @@ export default class GameEngine {
|
||||
this.isRunning = false
|
||||
}
|
||||
|
||||
public setScene(scene: Scene | string) {
|
||||
public async setScene(scene: Scene | string) {
|
||||
console.log('Setting scene', typeof scene === 'string' ? scene : scene.id)
|
||||
await this.currentScene?.destroy()
|
||||
this.currentScene = typeof scene === 'string' ? Scene.scenes[scene] : scene
|
||||
this.currentScene.setGameEngine(this)
|
||||
}
|
||||
|
||||
private update() {
|
||||
const now = new Date().getTime()
|
||||
if (!this.isRunning) {
|
||||
return
|
||||
}
|
||||
@ -106,9 +123,19 @@ export default class GameEngine {
|
||||
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)
|
||||
}
|
||||
this.currentScene?.update()
|
||||
setTimeout(() => {
|
||||
this.update()
|
||||
}, 0)
|
||||
const diff = new Date().getTime() - now
|
||||
if (diff > this.timer) {
|
||||
requestAnimationFrame(() => {
|
||||
this.update()
|
||||
})
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
// this.update()
|
||||
requestAnimationFrame(() => {
|
||||
this.update()
|
||||
})
|
||||
}, this.timer - diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user