Skip to content

Instantly share code, notes, and snippets.

@shohan4556
Created February 21, 2023 12:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shohan4556/b71d88fbc101aeb2d64a00487e70e959 to your computer and use it in GitHub Desktop.
Save shohan4556/b71d88fbc101aeb2d64a00487e70e959 to your computer and use it in GitHub Desktop.
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