add a basic terrain layout

This commit is contained in:
2025-01-19 00:59:17 +09:00
parent 0b949683a6
commit 0a4853aff9
6 changed files with 2291 additions and 41 deletions
+1
View File
@@ -333,6 +333,7 @@ export default class Entity {
if (!this.#moving || this.#dest == null) { return false } if (!this.#moving || this.#dest == null) { return false }
// TODO: bounding boxes to early discard a lot of collidables
const collidables = this.collidables() const collidables = this.collidables()
const fixedDest = SATX.clamp(SATX.fixCollisions(this.#dest, collidables, this.radius), this.game?.width, this.game?.height, this.radius) const fixedDest = SATX.clamp(SATX.fixCollisions(this.#dest, collidables, this.radius), this.game?.width, this.game?.height, this.radius)
+2 -2
View File
@@ -11,12 +11,12 @@ export default class Game {
averageTick = 0 averageTick = 0
currentTick = 0 currentTick = 0
entities = [] entities = []
height = 5000 height = 10000 * 1.6
projectiles = [] projectiles = []
secondToSlowestTick = 0 secondToSlowestTick = 0
terrains = [] terrains = []
tickRate = 30 tickRate = 30
width = 5000 width = 10000 * 1.6
#currentTiming = 0 #currentTiming = 0
#eventEmitter = new EventEmitter() #eventEmitter = new EventEmitter()
+62 -38
View File
@@ -6,6 +6,7 @@ import Game from './game.js'
import Team from './team.js' import Team from './team.js'
import Template from './template.js' import Template from './template.js'
import Terrain from './terrain.js' import Terrain from './terrain.js'
import Level from './level.js'
const app = new WebSocketExpress() const app = new WebSocketExpress()
const port = 1280 const port = 1280
@@ -15,6 +16,7 @@ app.use('/', express.static('public'))
app.use('/three/', express.static('node_modules/three')) app.use('/three/', express.static('node_modules/three'))
app.use('/@tweenjs/', express.static('node_modules/@tweenjs')) app.use('/@tweenjs/', express.static('node_modules/@tweenjs'))
app.use('/stats.js/', express.static('node_modules/stats.js')) app.use('/stats.js/', express.static('node_modules/stats.js'))
app.use('/tools/', express.static('tools'))
app.use(express.urlencoded({ extended: true })) app.use(express.urlencoded({ extended: true }))
app.ws('/ws', async (req, res) => { app.ws('/ws', async (req, res) => {
@@ -74,52 +76,73 @@ function laneScenario() {
game.spawnEntity(player1) game.spawnEntity(player1)
player1.attackAction(new Vector2(500, 150)) player1.attackAction(new Vector2(500, 150))
const player2 = new Entity(Template.player({ // const player2 = new Entity(Template.player({
id: '2', // id: '2',
spawnPosition: new Vector2(1600, 1800), // spawnPosition: new Vector2(1600, 1800),
team: Team.red, // team: Team.red,
})) // }))
game.spawnEntity(player2) // game.spawnEntity(player2)
player2.attackAction(new Vector2(1600, 1800)) // player2.attackAction(new Vector2(1600, 1800))
const midWallStart = new Vector2(600, 600)
const midWallEnd = new Vector2(1400, 1400)
const midWallMiddle = new Vector2(800, 1200)
const midWallThickness = midWallEnd.clone().sub(midWallStart).rotateAround(new Vector2(), -Math.PI / 2).normalize().multiplyScalar(50)
const midWallPoints = [
midWallStart,
midWallMiddle,
midWallEnd,
midWallEnd.clone().add(midWallThickness),
midWallMiddle.clone().add(midWallThickness),
midWallStart.clone().add(midWallThickness),
]
const midNorthWallOffset = new Vector2(-450, 450)
const midNorthWallPoints = midWallPoints.map((p) => p.clone().add(midNorthWallOffset))
const midNorthWall = new Terrain(midNorthWallPoints)
midNorthWall.id = 'midNorthWall'
game.addTerrain(midNorthWall)
const midSouthWallOffset = new Vector2(50, -50)
const midSouthWallPoints = midWallPoints.map((p) => p.clone().add(midSouthWallOffset))
const midSouthWall = new Terrain(midSouthWallPoints)
midSouthWall.id = 'midSouthWall'
game.addTerrain(midSouthWall)
const gameLogic = function gameLogic() { const gameLogic = function gameLogic() {
const game = this const game = this
const blueRoute = [new Vector2(600, 1350), new Vector2(1900, 1900)] const midRoute = [
const redRoute = [new Vector2(600, 1350), new Vector2(100, 100)] new Vector2(1544, 1572),
new Vector2(2748, 2792),
new Vector2(3628, 3688),
new Vector2(4992, 5000),
new Vector2(6272, 6188),
new Vector2(7252, 7200),
new Vector2(8436, 8408),
].map((p) => p.multiplyScalar(1.6))
const topRoute = [
new Vector2(868, 1740),
new Vector2(856, 3480),
new Vector2(808, 5944),
new Vector2(816, 7256),
new Vector2(976, 7772),
new Vector2(1388, 8384),
new Vector2(1948, 8940),
new Vector2(2392, 9152),
new Vector2(4168, 9196),
new Vector2(6548, 9168),
new Vector2(8288, 9176),
].map((p) => p.multiplyScalar(1.6))
const botRoute = [
new Vector2(1704, 812),
new Vector2(3460, 828),
new Vector2(5804, 768),
new Vector2(7332, 844),
new Vector2(8052, 1100),
new Vector2(8528, 1516),
new Vector2(9080, 2208),
new Vector2(9224, 2620),
new Vector2(9172, 4344),
new Vector2(9136, 6752),
new Vector2(9136, 8248),
].map((p) => p.multiplyScalar(1.6))
if ([(0 * game.tickRate), (1 * game.tickRate), (2 * game.tickRate)].includes(game.currentTick % (30 * game.tickRate))) { if ([(0 * game.tickRate), (1 * game.tickRate), (2 * game.tickRate)].includes(game.currentTick % (30 * game.tickRate))) {
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: false, route: blueRoute }))) game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: false, route: topRoute })))
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: false, route: redRoute }))) game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: false, route: midRoute })))
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: false, route: botRoute })))
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: false, route: topRoute.toReversed() })))
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: false, route: midRoute.toReversed() })))
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: false, route: botRoute.toReversed() })))
} }
if ([(3 * game.tickRate), (4 * game.tickRate), (5 * game.tickRate)].includes(game.currentTick % (30 * game.tickRate))) { if ([(3 * game.tickRate), (4 * game.tickRate), (5 * game.tickRate)].includes(game.currentTick % (30 * game.tickRate))) {
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: true, route: blueRoute }))) game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: true, route: topRoute })))
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: true, route: redRoute }))) game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: true, route: midRoute })))
game.spawnEntity(new Entity(Template.minion(Team.blue, { ranged: true, route: botRoute })))
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: true, route: topRoute.toReversed() })))
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: true, route: midRoute.toReversed() })))
game.spawnEntity(new Entity(Template.minion(Team.red, { ranged: true, route: botRoute.toReversed() })))
} }
} }
game.logic = gameLogic game.logic = gameLogic
@@ -128,6 +151,7 @@ function laneScenario() {
app.listen(port, () => { app.listen(port, () => {
console.log(`Server started! Visit http://localhost:${port}`) console.log(`Server started! Visit http://localhost:${port}`)
Level.terrains.map((points) => new Terrain(points.map((p) => p.multiplyScalar(1.6)))).forEach((terrain) => game.addTerrain(terrain))
laneScenario() laneScenario()
game.start() game.start()
+2133
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -9,7 +9,7 @@ export default class Template {
height: options.ranged ? 40 : 38, height: options.ranged ? 40 : 38,
logic: this.#minionLogic(options.route), logic: this.#minionLogic(options.route),
maxHealth: options.ranged ? 300 : 450, maxHealth: options.ranged ? 300 : 450,
position: team == Team.blue ? new Vector2(200, 200) : new Vector2(1800, 1800), position: options.route?.at(0) ?? new Vector2(0, 0),
radius: 48, radius: 48,
speed: 325, speed: 325,
team, team,
+92
View File
@@ -0,0 +1,92 @@
<html>
<head>
<title>Terrain Creator</title>
<style>
* {
box-sizing: border-box;
}
html, body {
background-color: black;
font-family: sans-serif;
}
html {
padding: 0;
}
body {
margin: 0;
}
#map {
background-color: white;
background-image: url('./background.png');
background-size: cover;
}
.point {
position: absolute;
border-radius: 50%;
margin-top: -5px;
margin-left: -5px;
width: 10px;
height: 10px;
background-color: red;
border: 1px solid white;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var width = null
var height = null
var scale = null
var points = []
window.addEventListener('load', () => {
const params = Object.fromEntries(new URLSearchParams(window.location.search).entries())
width = params.width
height = params.height
scale = params.scale
if (width == null) {
width = prompt('Width: ')
}
if (height == null) {
height = prompt('Height: ')
}
if (scale == null) {
scale = prompt('Scale: ')
}
const map = document.getElementById('map')
map.style.width = `${width / scale}px`
map.style.height = `${height / scale}px`
map.addEventListener('contextmenu', (event) => event.preventDefault())
map.addEventListener('mousedown', (event) => {
if (event.button == 2) {
console.log(`\n\n[\n` + points.map((p) => ` new Vector2(${p.x}, ${p.y}),`).join(`\n`) + `\n],\n`)
points = []
map.innerHTML = ''
return
}
if (event.button == 0) {
const x = Math.floor(event.pageX * scale)
const y = Math.floor(height - (event.pageY * scale))
points.push({ x, y })
const point = document.createElement('div')
point.classList.add('point')
point.style.left = event.pageX
point.style.top = event.pageY
map.appendChild(point)
return
}
})
})
</script>
</body>
</html>