Initial commit: Arcanum TD — medieval fantasy tower defense
Vite + React + PixiJS + TypeScript. Features: - 4-level campaign (King's Road → Obsidian Keep) - Isometric 2.5D grid with ley-line mechanics - ECS architecture (entities, components, systems) - 4 tower types, hero spellcaster, 10+ enemy types - Lich King boss with 3-phase AI - Meta-progression: essence, rune unlocks - Full UI redesign with fantasy design system Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import { Container, Graphics } from 'pixi.js'
|
||||
import type { Entity } from '@/game/core/EntityManager'
|
||||
import type { TransformComp, ProjectileComp, RenderComp } from '@/game/components'
|
||||
import { getWorldContainer } from '@/game/rendering/WorldContext'
|
||||
|
||||
export function createArrow(
|
||||
entity: Entity,
|
||||
startX: number,
|
||||
startY: number,
|
||||
targetId: number,
|
||||
damage: number,
|
||||
ownerId: number,
|
||||
): void {
|
||||
const container = new Container()
|
||||
|
||||
const gfx = new Graphics()
|
||||
// arrow shaft
|
||||
gfx.rect(-6, -1, 10, 2)
|
||||
gfx.fill({ color: 0xc9a14a })
|
||||
// arrowhead
|
||||
gfx.poly([-6, -3, -6, 3, -12, 0])
|
||||
gfx.fill({ color: 0xe8e0c0 })
|
||||
// trail glow
|
||||
gfx.rect(4, -0.5, 8, 1)
|
||||
gfx.fill({ color: 0xc9a14a, alpha: 0.4 })
|
||||
|
||||
container.addChild(gfx)
|
||||
container.x = startX
|
||||
container.y = startY
|
||||
getWorldContainer().addChild(container)
|
||||
|
||||
const transform: TransformComp = { x: startX, y: startY, rotation: 0 }
|
||||
const projectile: ProjectileComp = {
|
||||
speed: 360,
|
||||
targetId,
|
||||
damage,
|
||||
damageType: 'physical',
|
||||
ownerId,
|
||||
hitRadius: 12,
|
||||
projectileType: 'arrow',
|
||||
}
|
||||
const render: RenderComp = { container, hpBar: null, label: null }
|
||||
|
||||
Object.assign(entity, { transform, projectile, render })
|
||||
entity.tags.add('projectile')
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Container, Graphics } from 'pixi.js'
|
||||
import type { Entity } from '@/game/core/EntityManager'
|
||||
import type { TransformComp, ProjectileComp, RenderComp } from '@/game/components'
|
||||
import { getWorldContainer } from '@/game/rendering/WorldContext'
|
||||
|
||||
export function createFireball(
|
||||
entity: Entity,
|
||||
startX: number,
|
||||
startY: number,
|
||||
targetId: number,
|
||||
damage: number,
|
||||
ownerId: number,
|
||||
): void {
|
||||
const container = new Container()
|
||||
|
||||
const gfx = new Graphics()
|
||||
gfx.circle(0, 0, 7)
|
||||
gfx.fill({ color: 0xff6600 })
|
||||
gfx.circle(0, 0, 4)
|
||||
gfx.fill({ color: 0xffdd00 })
|
||||
|
||||
const trail = new Graphics()
|
||||
trail.circle(4, 0, 4)
|
||||
trail.fill({ color: 0xff4400, alpha: 0.5 })
|
||||
trail.circle(9, 0, 2.5)
|
||||
trail.fill({ color: 0xff2200, alpha: 0.3 })
|
||||
|
||||
container.addChild(trail, gfx)
|
||||
container.x = startX
|
||||
container.y = startY
|
||||
getWorldContainer().addChild(container)
|
||||
|
||||
Object.assign(entity, {
|
||||
transform: { x: startX, y: startY, rotation: 0 } as TransformComp,
|
||||
projectile: { speed: 280, targetId, damage, damageType: 'magic', ownerId, hitRadius: 14, projectileType: 'fireball' } as ProjectileComp,
|
||||
render: { container, hpBar: null, label: null } as RenderComp,
|
||||
})
|
||||
entity.tags.add('projectile')
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Container, Graphics } from 'pixi.js'
|
||||
import type { Entity } from '@/game/core/EntityManager'
|
||||
import type { TransformComp, ProjectileComp, RenderComp } from '@/game/components'
|
||||
import { getWorldContainer } from '@/game/rendering/WorldContext'
|
||||
|
||||
export function createIcicle(
|
||||
entity: Entity,
|
||||
startX: number,
|
||||
startY: number,
|
||||
targetId: number,
|
||||
damage: number,
|
||||
ownerId: number,
|
||||
): void {
|
||||
const container = new Container()
|
||||
|
||||
const gfx = new Graphics()
|
||||
gfx.poly([0, -8, -3, 0, 0, 5, 3, 0])
|
||||
gfx.fill({ color: 0xaaeeff })
|
||||
gfx.poly([0, -8, -3, 0, 0, 5, 3, 0])
|
||||
gfx.stroke({ color: 0x6ecbd5, width: 1 })
|
||||
|
||||
container.addChild(gfx)
|
||||
container.x = startX
|
||||
container.y = startY
|
||||
getWorldContainer().addChild(container)
|
||||
|
||||
Object.assign(entity, {
|
||||
transform: { x: startX, y: startY, rotation: 0 } as TransformComp,
|
||||
projectile: { speed: 320, targetId, damage, damageType: 'magic', ownerId, hitRadius: 10, projectileType: 'icicle' } as ProjectileComp,
|
||||
render: { container, hpBar: null, label: null } as RenderComp,
|
||||
})
|
||||
entity.tags.add('projectile')
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Container, Graphics } from 'pixi.js'
|
||||
import type { Entity } from '@/game/core/EntityManager'
|
||||
import type { TransformComp, ProjectileComp, RenderComp } from '@/game/components'
|
||||
import { getWorldContainer } from '@/game/rendering/WorldContext'
|
||||
|
||||
export function createLightning(
|
||||
entity: Entity,
|
||||
startX: number,
|
||||
startY: number,
|
||||
targetId: number,
|
||||
damage: number,
|
||||
ownerId: number,
|
||||
): void {
|
||||
const container = new Container()
|
||||
|
||||
const gfx = new Graphics()
|
||||
gfx.circle(0, 0, 5)
|
||||
gfx.fill({ color: 0xffffff })
|
||||
gfx.circle(0, 0, 3)
|
||||
gfx.fill({ color: 0xaaaaff })
|
||||
// small bolt shape
|
||||
gfx.poly([2, -6, -1, 0, 2, 0, -2, 6])
|
||||
gfx.stroke({ color: 0xffd700, width: 1.5 })
|
||||
|
||||
container.addChild(gfx)
|
||||
container.x = startX
|
||||
container.y = startY
|
||||
getWorldContainer().addChild(container)
|
||||
|
||||
Object.assign(entity, {
|
||||
transform: { x: startX, y: startY, rotation: 0 } as TransformComp,
|
||||
projectile: { speed: 500, targetId, damage, damageType: 'magic', ownerId, hitRadius: 12, projectileType: 'lightning' } as ProjectileComp,
|
||||
render: { container, hpBar: null, label: null } as RenderComp,
|
||||
})
|
||||
entity.tags.add('projectile')
|
||||
}
|
||||
Reference in New Issue
Block a user