Created
February 21, 2023 12:07
-
-
Save shohan4556/b71d88fbc101aeb2d64a00487e70e959 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Parcels from 'components/phaser/Parcels'; | |
import { Vector2 } from 'types'; | |
import _ from 'lodash'; | |
import { scene } from 'components/controllers/SceneController'; | |
import { GAME_CONFIG, TILE_SIZE } from 'shared_code/constants/const.game'; | |
import Players from 'components/phaser/Players'; | |
import GlobalState from 'contexts/GlobalState'; | |
import GameController from 'components/controllers/GameController'; | |
const DEFAULT_ZOOM = 1; | |
let ALLOW_UNLIMITED_ZOOM_OUT = false; | |
let WINDOW_WIDTH = 0; | |
let WINDOW_HEIGHT = 0; | |
let WINDOW_RATIO = 1; | |
let ACTIVE_PARCEL = null; | |
let MAX_ZOOM_OUT = 0.25; | |
let lastZoomTween; | |
const ZOOM_FACTOR = 1.2; | |
const ZOOM_DURATION = 100; | |
const MAP_SIZE = { width: 17408, height: 10240 }; | |
const MID_POINT = { x: 0, y: 0 }; | |
const CAMERA_BOUNDS = { left: 0, right: 0 }; | |
const STAR_FIELD = { width: 0, height: 0, midX: 0, midY: 0 }; | |
const AOI = { width: 0, height: 0 }; | |
export const interpolatePositionUpdate = ( | |
object: Phaser.GameObjects.Sprite | Phaser.GameObjects.Image | Phaser.GameObjects.Container | Phaser.GameObjects.Graphics, | |
position: { x: number; y: number }, | |
FPSMultiplier?: number, | |
): void => { | |
if (!scene || !object) return; | |
const duration = FPSMultiplier ? FPSMultiplier * GAME_CONFIG.gameUpdateIntervalMS : GAME_CONFIG.gameUpdateIntervalMS; | |
scene.tweens.add({ | |
targets: object, | |
x: position.x, | |
y: position.y, | |
duration, | |
}); | |
}; | |
export function setDefaultZoom(width, height, AOIHeight?: number, AOIWidth?: number) { | |
MAP_SIZE.width = width; | |
MAP_SIZE.height = height; | |
AOI.width = AOIWidth || width; | |
AOI.height = AOIHeight || height; | |
MID_POINT.x = width * 0.5; | |
MID_POINT.y = height * 0.5; | |
CAMERA_BOUNDS.left = (width - WINDOW_WIDTH / MAX_ZOOM_OUT) * 0.5; | |
CAMERA_BOUNDS.right = width - CAMERA_BOUNDS.left; | |
} | |
export function toggleUnlimitedZoomOut(allowUnlimitedZoomOutState) { | |
if (ALLOW_UNLIMITED_ZOOM_OUT !== allowUnlimitedZoomOutState) { | |
ALLOW_UNLIMITED_ZOOM_OUT = allowUnlimitedZoomOutState; | |
CAMERA_BOUNDS.left = (MAP_SIZE.width - window.innerWidth / MAX_ZOOM_OUT) * 0.5; | |
CAMERA_BOUNDS.right = MAP_SIZE.width - CAMERA_BOUNDS.left; | |
setZoomDefaults(); | |
} | |
} | |
export const getMapPos = (): string => { | |
return `${GlobalState.PHASER.state.playerPosition.x * TILE_SIZE}, ${GlobalState.PHASER.state.playerPosition.y * TILE_SIZE}`; | |
}; | |
export function getDefaultCameraSettings() { | |
return { | |
zoom: MAX_ZOOM_OUT || WINDOW_WIDTH / MAP_SIZE.width, | |
left: CAMERA_BOUNDS.left, | |
right: CAMERA_BOUNDS.right, | |
width: MAP_SIZE.width, | |
height: MAP_SIZE.height, | |
}; | |
} | |
export const getAngleByDirV2 = (dir: Vector2): number => { | |
return (Math.atan2(dir.y, dir.x) * 180) / Math.PI; // correct way to get angle | |
// return 50 * Math.atan2(dir.y, dir.x) - 90; | |
}; | |
export function getPhaserDirV2(player: Vector2, target: Vector2): number { | |
return Math.atan((target.x - player.x) / (target.y - player.y)); | |
} | |
export function getPhaserAngleByDirV2(dir: Vector2): number { | |
const angleInRad = new Phaser.Math.Vector2(dir.x, dir.y).angle(); // angle in radians | |
return Phaser.Math.RadToDeg(angleInRad); // return angle in degrees | |
} | |
// const sub = subtractVectors(pointerWorld, player); | |
// const phaserAngle = new Phaser.Math.Vector2(sub.x, sub.y); | |
// return Phaser.Math.RadToDeg(phaserAngle.angle()); | |
export function getAngleByDir(dir: Vector2): number { | |
const angle = Math.atan2(dir.x, dir.y) + 90; | |
const degree = (180 * angle) / Math.PI; | |
return (360 + Math.round(degree)) % 360; | |
// return (Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI); | |
} | |
export function getDirectionByPosition(currentPosition: Vector2, targetPosition: Vector2): Vector2 { | |
const currentVec = new Phaser.Math.Vector2(currentPosition.x, currentPosition.y); | |
const targetVec = new Phaser.Math.Vector2(targetPosition.x, targetPosition.y); | |
const directionVec = targetVec.subtract(currentVec).normalize(); | |
const { x, y } = directionVec; | |
// check and see what absolute val of x and y is bigger to determine what will be the direction if both of them are 1. | |
const lead = Math.abs(x) >= Math.abs(y) ? 'x' : 'y'; | |
for (const prop in directionVec) { | |
// for the lead return -1 if value is lower than -0.5 or 1 if is bigger than 0.5. For the other prop return 0. | |
directionVec[prop] = prop === lead ? (directionVec[prop] < -0.5 ? -1 : 1) : 0; | |
} | |
return directionVec; | |
} | |
export function addGrid(x, y, width, height) { | |
if (!scene.grid) { | |
// const grid = scene.add.grid(scene.map.widthInPixels / 2, scene.map.heightInPixels / 2, scene.map.widthInPixels, scene.map.heightInPixels, 32, 32); | |
// scene.grid = scene.add.grid(x, y, width, height, 32, 32); | |
// scene.grid.setDepth(-1); | |
// scene.grid.setAlpha(0.4); | |
// scene.grid.setOutlineStyle(0x7f00ff); | |
} | |
} | |
export function createParallax(): void { | |
scene.timer = 0; | |
const bgWidth = window.innerWidth; | |
const bgHeight = window.innerHeight; | |
scene.stars = scene.add.tileSprite(0, 0, bgWidth, bgHeight, 'stars', 0).setOrigin(0.5); | |
// scene.stars.setBlendMode(Phaser.BlendModes.ADD); | |
scene.stars.setDepth(-2); | |
scene.starField = scene.add.tileSprite(0, 0, bgWidth, bgHeight, 'large_starfield').setOrigin(0.5); | |
// scene.starField.setBlendMode(Phaser.BlendModes.ADD); | |
scene.starField.setDepth(-3); | |
scene.starsFrame = 0; | |
scene.starFieldFrame = 0; | |
// scene.stars.setAlpha(0); | |
// scene.starField.setAlpha(0); | |
STAR_FIELD.width = bgWidth; | |
STAR_FIELD.height = bgHeight; | |
STAR_FIELD.midX = bgWidth * 0.5; | |
STAR_FIELD.midY = bgHeight * 0.5; | |
// hide the starfields until the first update to avoid FOUC | |
// scene.stars.setAlpha(0); | |
// scene.starField.setAlpha(0); | |
// scene.stars.setScale(0.23); | |
// scene.starField.setScale(0.23); | |
scene.stars.x = scene.starField.x = STAR_FIELD.midX; | |
scene.stars.y = scene.starField.y = STAR_FIELD.midY; | |
} | |
export const random = (list) => { | |
return list[Math.floor(Math.random() * list.length)]; | |
}; | |
export function randomIntInRange(min, max) { | |
return Math.round(min + Math.random() * (max - min)); | |
} | |
export function updateParallax({ id }, delta: number) { | |
if (!scene.stars || !scene.starField || !scene[id]) return; | |
const scrollX = scene.cameras.main.scrollX; // scene.cameras.main.worldView.x; | |
const scrollY = scene.cameras.main.scrollY; // scene.cameras.main.worldView.y; | |
// star field width = 5160 | |
// star field height = 2865 | |
// 2383 1321 | |
scene.stars.setTilePosition(scrollX * 0.02, scrollY * 0.02); | |
scene.starField.setTilePosition(scrollX * 0.04, scrollY * 0.04); | |
if (id && scene[id]) { | |
// given we want a star BG scale value of 4 at .2 zoom (max zoom out) and 3 at 2 zoom (max zoom in) | |
// handy: https://www.dcode.fr/function-equation-finder | |
const zoomEquationValue = 4.33333 - 1.66667 * scene.zoom; | |
scene.stars.setScale(zoomEquationValue); | |
scene.starField.setScale(zoomEquationValue); | |
if (scene.stars.width * scene.zoom < window.innerWidth) { | |
scene.stars.width = scene.starField.width = window.innerWidth / scene.zoom; | |
} | |
if (scene.stars.height * scene.zoom < window.innerHeight) { | |
scene.stars.height = scene.starField.height = window.innerHeight / scene.zoom; | |
} | |
if (scrollX > 0) { | |
scene.stars.x = scene.starField.x = Phaser.Math.Clamp(scene[id].x, STAR_FIELD.midX, MAP_SIZE.width - STAR_FIELD.midX); | |
} | |
if (scrollY > 0) { | |
scene.stars.y = scene.starField.y = Phaser.Math.Clamp(scene[id].y, STAR_FIELD.midY, MAP_SIZE.height - STAR_FIELD.midY); | |
} | |
} | |
// create manual animation | |
scene.timer += delta; | |
if (scene.timer > 400) { | |
scene.timer -= 400; | |
scene.stars.setFrame(scene.starsFrame); | |
scene.starsFrame++; | |
scene.starFieldFrame++; | |
if (scene.starsFrame === 3) { | |
scene.starsFrame = 0; | |
} | |
} | |
} | |
export function addText(currentAccount: string) { | |
const text = `account:${currentAccount}`; | |
scene.add.text(16, 16, text).setFontSize(22).setFontFamily('Pixelar').setColor('#00ffff'); | |
} | |
export const toggleFollowGotchi = (state) => { | |
if (state) scene.cameras.main.startFollow(scene[Players.selectedPlayer.id], true); | |
else scene.cameras.main.stopFollow(); | |
}; | |
export const focusParcel = (parcel) => { | |
// focus parcel when build mode triggered | |
const { position, size } = parcel; | |
const x = (position.x + size.width / 2) * 64; | |
const y = (position.y + size.height / 2) * 64; | |
ACTIVE_PARCEL = { | |
position: { x: x, y: y }, | |
size: { width: size.width * 64, height: size.height * 64 }, | |
}; | |
toggleFollowGotchi(false); | |
dragMap(true); | |
}; | |
const throttleZoomLevel = _.throttle( | |
(deltaY, scene) => { | |
if (deltaY < 0) setZoomLevel(scene.zoom * ZOOM_FACTOR); | |
else if (deltaY > 0) setZoomLevel(scene.zoom / ZOOM_FACTOR); | |
}, | |
ZOOM_DURATION, | |
{ leading: true, trailing: true }, | |
); | |
export function handleZoom() { | |
scene.zoom = MAX_ZOOM_OUT; | |
scene.currentZoomIcon = 'zoomOut'; | |
scene.input.on('wheel', (pointer, gameobjects, deltaX, deltaY, deltaZ) => { | |
// if (scene.isMoving || Installations.buildModeState) return; | |
throttleZoomLevel(deltaY, scene); | |
// if (deltaY < 0) scene.zoom += 0.01; | |
// else if (deltaY > 0) scene.zoom -= 0.01; | |
// // round scene.zoom to second decimal to avoid aliasing (floating point math rounding errors) | |
}); | |
} | |
// get a phaser object by group | |
export const getGroupMemberById = (id: string, group: 'missiles' | 'meleeGroup') => { | |
if (!scene?.[group]) return; | |
return scene[group].get(id); | |
}; | |
export function checkMinimumZoom() { | |
if (scene.zoom < MAX_ZOOM_OUT && !ALLOW_UNLIMITED_ZOOM_OUT) { | |
// we are allowing zoom out to 175% of AOI size | |
// this 25% leeway should still allow enough time to preload the next zone while moving | |
scene.zoom = MAX_ZOOM_OUT || (WINDOW_WIDTH / WINDOW_RATIO / AOI.width) * 1.75; | |
} | |
} | |
export function createContainer(width, height, debugFill?: boolean) { | |
const container = scene.add?.container(0, 0); | |
container.setSize(width, height); | |
if (debugFill) { | |
const rect = new Phaser.Geom.Rectangle(-width / 2, -height / 2, width, height); | |
const graphics = scene.add.graphics(); | |
graphics.fillRectShape(rect).fillStyle(0xfffff); | |
graphics.setName('mask'); | |
container.add(graphics); | |
} | |
return container; | |
} | |
export const dragMap = (state: boolean): void => { | |
if (!scene) return; | |
// @ts-expect-error | |
const drag = scene.plugins.get('rexpinchplugin').add(scene); | |
if (state && ACTIVE_PARCEL) { | |
drag.on('drag1', (_drag) => { | |
const width = WINDOW_WIDTH * 0.5; | |
const height = WINDOW_HEIGHT * 0.5; | |
const centreX = Math.round(ACTIVE_PARCEL.position.x - width); | |
const centreY = Math.round(ACTIVE_PARCEL.position.y - height); | |
const parcelWidth = Math.round(ACTIVE_PARCEL.size.width * 0.25); | |
const parcelHeight = Math.round(ACTIVE_PARCEL.size.height * 0.25); | |
const left = centreX - parcelWidth; | |
const right = centreX + parcelWidth; | |
const top = centreY - parcelHeight; | |
const bottom = centreY + parcelHeight; | |
let scrollX = scene.cameras.main.scrollX - _drag.drag1Vector.x / scene.cameras.main.zoom; | |
let scrollY = scene.cameras.main.scrollY - _drag.drag1Vector.y / scene.cameras.main.zoom; | |
if (scrollX > right) scrollX = right; | |
else if (scrollX < left) scrollX = left; | |
if (scrollY > bottom) scrollY = bottom; | |
else if (scrollY < top) scrollY = top; | |
scene.cameras.main.scrollX = scrollX; | |
scene.cameras.main.scrollY = scrollY; | |
}); | |
} else drag.off('drag1'); | |
}; | |
export function setZoomLevel(zoomLevel, duration = 0) { | |
let updatedZoomLevel = Phaser.Math.Clamp(zoomLevel, MAX_ZOOM_OUT, 2); | |
console.log('set zoom level', updatedZoomLevel); | |
updatedZoomLevel = Math.round(updatedZoomLevel * 32) / 32; | |
if (lastZoomTween?.isPlaying()) { | |
lastZoomTween.stop(); | |
lastZoomTween.remove(); | |
} | |
lastZoomTween = scene.tweens.addCounter({ | |
from: scene.zoom, | |
to: updatedZoomLevel, | |
duration: duration || ZOOM_DURATION, | |
// ease: Phaser.Math.Easing.Quartic.In, | |
onUpdate: (tween) => { | |
updateZoomLevel(tween.getValue()); | |
}, | |
}); | |
} | |
export function setZoomDefaults(init?: boolean) { | |
WINDOW_WIDTH = Number(window.innerWidth); | |
WINDOW_HEIGHT = Number(window.innerHeight); | |
WINDOW_RATIO = 1; | |
if (WINDOW_HEIGHT > WINDOW_WIDTH) WINDOW_RATIO = WINDOW_WIDTH / WINDOW_HEIGHT; | |
// we are allowing zoom out to 175% of AOI size | |
// this 25% leeway should still allow enough time to preload the next zone while moving | |
let zoom = WINDOW_WIDTH / WINDOW_RATIO / (ALLOW_UNLIMITED_ZOOM_OUT ? MAP_SIZE.width : AOI.width * 1.75); | |
if (GameController.MAP === 'aarena') zoom = 0.25; | |
if (ALLOW_UNLIMITED_ZOOM_OUT) MAX_ZOOM_OUT = 0.05; | |
else MAX_ZOOM_OUT = Math.round(zoom * 64) / 64; | |
if (scene && init) { | |
scene.zoom = MAX_ZOOM_OUT || zoom; | |
} else { | |
// if (scene.zoom < MAX_ZOOM_OUT) setZoomLevel(MAX_ZOOM_OUT, 0); | |
} | |
} | |
function updateZoomLevel(zoomLevel) { | |
scene.zoom = zoomLevel; | |
if (GlobalState.SETTINGS.state.fadeGrid || ALLOW_UNLIMITED_ZOOM_OUT) { | |
Parcels.fadeOut(scene.zoom); | |
// scene.grid?.setAlpha(Math.min(scene.zoom / 2, 0.75)); | |
// if (scene.zoom >= 0.8) { | |
// scene.grid?.setAlpha(0.4); | |
// } | |
if (scene?.stars && scene.starField) { | |
scene.stars.setAlpha(scene.zoom * 3); | |
scene.starField.setAlpha(scene.zoom * 4); | |
} | |
// if (scene.zoom <= 0.27) { | |
// scene.grid?.setAlpha(0); | |
// // scene.starField?.setAlpha(0); | |
// // scene.stars?.setAlpha(0); | |
// } else { | |
// // scene.starField?.setTileScale(3); | |
// // scene.stars?.setTileScale(1); | |
// // scene.cameras.main.setBackgroundColor('rgba(0,0,0,0)'); | |
// } | |
} | |
// scene.cameras.main.setBackgroundColor('rgba(33, 0, 87, '+(1-scene.zoom/2)+')'); | |
scene.cameras.main.zoom = scene.zoom; | |
// scene.cameras.main.zoomTo(scene.zoom, 100, 'Linear', false); | |
// scene.stars.setScale(1 / scene.zoom); | |
// scene.starField.setScale(1 / scene.zoom); | |
GlobalState.PHASER.dispatch({ | |
type: 'UPDATE_ZOOM_SLIDER', | |
zoom: (scene.zoom - MAX_ZOOM_OUT) / getDefaultZoomRange(), | |
}); | |
// if (scene.intro) { | |
// scene.intro.setScale(1 / scene.cameras.main.zoom, 1 / scene.cameras.main.zoom); | |
// } | |
// if (scene.outro) { | |
// scene.outro.setScale(1 / scene.cameras.main.zoom, 1 / scene.cameras.main.zoom); | |
// } | |
checkZoom(); | |
} | |
export const showStarfield = (enable: boolean) => { | |
if (GlobalState.SETTINGS.state.allowStarField) { | |
scene.stars.setVisible(enable); | |
scene.starField.setVisible(enable); | |
} | |
}; | |
function updateCameraBounds() { | |
const mapWidthDisplay = scene.zoom * MAP_SIZE.width; | |
if (mapWidthDisplay < WINDOW_WIDTH) { | |
scene.cameras.main.setBounds(CAMERA_BOUNDS.left, 0, CAMERA_BOUNDS.right, MAP_SIZE.height); | |
} else { | |
scene.cameras.main.setBounds(0, 0, MAP_SIZE.width, MAP_SIZE.height); | |
} | |
} | |
export function getDefaultMaxZoomOut() { | |
return MAX_ZOOM_OUT; | |
} | |
export function getDefaultZoomRange() { | |
return 2 - MAX_ZOOM_OUT; | |
} | |
export function checkZoom() { | |
updateCameraBounds(); | |
if (scene.zoom < DEFAULT_ZOOM && !scene.maxZoomOut) { | |
scene.maxZoomOut = true; | |
// showStarfield(scene, false); | |
GlobalState.PHASER.dispatch({ | |
type: 'UPDATE_MAX_ZOOM_OUT', | |
maxZoomOut: scene.maxZoomOut, | |
}); | |
} else if (scene.zoom >= DEFAULT_ZOOM && scene.maxZoomOut) { | |
scene.maxZoomOut = false; | |
// showStarfield(scene, true); | |
GlobalState.PHASER.dispatch({ | |
type: 'UPDATE_MAX_ZOOM_OUT', | |
maxZoomOut: scene.maxZoomOut, | |
}); | |
} | |
} | |
export function handleZoomSlider(scene, zoom) { | |
const zoomLevel = MAX_ZOOM_OUT + getDefaultZoomRange() * zoom; | |
const dz = Math.abs(zoomLevel - scene.zoom); | |
let zoomDuration = ZOOM_DURATION; | |
if (dz > 0.1) zoomDuration *= dz * 5; | |
setZoomLevel(zoomLevel, zoomDuration); | |
} | |
export function handleZoomClick() { | |
if (!scene.maxZoomOut) { | |
if (scene.zoom !== DEFAULT_ZOOM) scene.zoom = DEFAULT_ZOOM; | |
else scene.zoom = MAX_ZOOM_OUT; | |
} else scene.zoom = DEFAULT_ZOOM; | |
checkZoom(); | |
if (GlobalState.SETTINGS.state.fadeGrid) { | |
Parcels.fadeOut(scene.zoom); | |
// scene.grid.setAlpha(scene.zoom / 2); | |
// if (scene.zoom >= 0.8) { | |
// scene.grid.setAlpha(0.4); | |
// } | |
} | |
scene.cameras.main.setZoom(scene.zoom); | |
} | |
let debugShapes = []; | |
export function createTestBodies(scene, data) { | |
const color = new Phaser.Display.Color(); | |
if (data.rects) { | |
const clearTestOverlay = data.rects && data.rects.length === 0; | |
if (clearTestOverlay) { | |
debugShapes.forEach(function (shape) { | |
shape.destroy(); | |
}); | |
debugShapes = []; | |
} else { | |
if (data.rects) { | |
data.rects.forEach(({ x, y, width, height }) => { | |
color.random(100); | |
const graphics = scene?.add?.graphics().setDepth(1000); | |
graphics.name = 'debug_shape'; | |
graphics.fillStyle(color.color, 0.7); | |
graphics.fillRect(x - width / 2, y - height / 2, width, height); | |
debugShapes.push(graphics); | |
}); | |
} | |
if (data.verts) { | |
data.verts.forEach((vert) => { | |
createVertsPath(vert); | |
}); | |
} | |
} | |
} else if (data.aoiRects) { | |
debugShapes.forEach(function (shape) { | |
shape.destroy(); | |
}); | |
debugShapes = []; | |
data.aoiRects.forEach(({ x, y, width, height }) => { | |
const graphics = scene.add.graphics().setDepth(1000); | |
const aoiLineWidth = 32; | |
graphics.name = 'debug_shape'; | |
graphics.lineStyle(aoiLineWidth, 0xffffff, 0.15); | |
graphics.strokeRect(x + aoiLineWidth / 2, y + aoiLineWidth / 2, width - aoiLineWidth, height - aoiLineWidth); | |
debugShapes.push(graphics); | |
}); | |
} | |
} | |
export function createVertsPath(data) { | |
// console.log('data', data); | |
const { vertSet, x, y, width, height } = data; | |
// console.log(vertSet); | |
const graphics = scene?.add?.graphics({ x, y }); | |
graphics.lineStyle(2, 0x00aa00); | |
graphics.beginPath(); | |
graphics.setDepth(200); | |
graphics.moveTo(vertSet[0].x - width / 2, vertSet[0].y - height / 2); | |
for (let i = 1; i < vertSet.length; i++) { | |
graphics.lineTo(vertSet[i].x - width / 2, vertSet[i].y - height / 2); | |
} | |
graphics.closePath(); | |
graphics.fillStyle(0x00ff00, 0.4); | |
graphics.strokePath(); | |
} | |
export const getOriginByDirection = ({ x, y }: Vector2): Vector2 => { | |
return { | |
x: x <= 0 ? (x < 0 ? 1 : 0.5) : 0, | |
y: y <= 0 ? (y < 0 ? 1 : 0.5) : 0, | |
}; | |
}; | |
export const getOffsetByDirection = (direction: Vector2, factor: number): Vector2 => { | |
return { x: direction.x * factor, y: direction.y * factor }; | |
}; | |
export function getDynamics(diff: number): 1 | 2 | 3 { | |
if (diff >= 0 && diff <= 75) { | |
return 1; | |
} else if (diff >= 76 && diff <= 150) { | |
return 2; | |
} else if (diff >= 151) { | |
return 3; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment