this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
import { Field } from './field'; import { FootballObject } from './object'; import { BASE_URL } from './const'; import { Mesh, MeshBasicMaterial, Scene, Texture } from 'three'; export enum PlayerType { DEFENDER, MIDFIELDER, FORWARD } export interface IPlayerOptions { isCpu: boolean; } const MIN_SPEED = 0.03; const MAX_SPEED = 0.07; export class Player extends FootballObject { protected options: IPlayerOptions; protected mesh: Mesh; protected type: PlayerType; protected startX: number; protected startZ: number; protected targetX: number; protected targetZ: number; protected speed: number; public isActive = true; public isRun = false; public isCurrent = false; static ready: Promise<any>; static mesh: Mesh; constructor(scene: Scene, options: IPlayerOptions) { super(scene); this.options = options; this.speed = (Math.random() * (MAX_SPEED - MIN_SPEED) + MIN_SPEED); } static init(scene: Scene): Promise<any> { if (!Player.ready) { Player.ready = new Promise((resolve, reject) => { const loader = new THREE.SEA3D({ autoPlay: true, container: scene, multiplier: .6 }); loader.onComplete = () => { const mesh: Mesh = loader.getMesh('Player'); const hat = loader.getMesh('Hat'); if (hat) { hat.visible = false; } mesh.scale.set(.02, .02, .02); mesh.position.y = 2; mesh.visible = false; Player.mesh = mesh; resolve(); }; loader.load(`${ BASE_URL }/resources/models/player1.sea`); }); } return Player.ready; } }
clone() { this.mesh = Player.mesh.clone(); this.scene.add(this.mesh); }
const hat = loader.getMesh('Hat'); if (hat) { hat.visible = false; }
setTexture(textureName: string) { const loader = new THREE.TextureLoader(); loader.load(`${ BASE_URL }/resources/textures/${textureName}`, (texture: Texture) => { this.mesh.material = this.mesh.material.clone(); texture.flipY = false; (<MeshBasicMaterial> this.mesh.material).map = texture; }); }
moveTo(x: number, z: number) { this.startX = this.mesh.position.x; this.startZ = this.mesh.position.z; this.targetX = x; this.targetZ = z; this.isRun = true; } animate(options: any) { if (this.isCurrent && this.isRun && !this.options.isCpu) { this.run(); } else if (this.isRun) { const distanceX = this.targetX - this.startX; const distanceZ = this.targetZ - this.startZ; const newX = this.mesh.position.x + this.speed * (distanceX > 0 ? 1 : -1); const newZ = this.mesh.position.z + this.speed * (distanceZ > 0 ? 1 : -1); let isRun = false; if (Field.isInsideByX(newX) && ((distanceX > 0 && this.mesh.position.x < this.targetX) || (distanceX < 0 && this.mesh.position.x > this.targetX))) { this.mesh.position.x = newX; isRun = true; } if (Field.isInsideByZ(newZ) && ((distanceZ > 0 && this.mesh.position.z < this.targetZ) || (distanceZ < 0 && this.mesh.position.z > this.targetZ))) { this.mesh.position.z = newZ; isRun = true; } this.isRun = isRun; this.run(); } else if (!options.isStarted) { this.idleStatic(); } else { this.idleDynamic(); } }
import { Player, PlayerType } from './player'; import { FIELD_WIDTH, FIELD_HEIGHT } from './field'; import { Utils } from './utils'; import { Scene } from 'three'; import { FootballObject } from './object'; export class Team { protected scene: Scene; protected options: ITeamOptions; protected players: Player[] = []; protected currentPlayer: Player; protected score = 0; withBall = false; }
protected getPlayersType(): PlayerType[] { return [ PlayerType.DEFENDER, PlayerType.DEFENDER, PlayerType.DEFENDER, PlayerType.DEFENDER, PlayerType.MIDFIELDER, PlayerType.MIDFIELDER, PlayerType.MIDFIELDER, PlayerType.MIDFIELDER, PlayerType.FORWARD, PlayerType.FORWARD ] }
createPlayers() { return new Promise((resolve, reject) => { Player.init(this.scene) .then(() => { const types: PlayerType[] = this.getPlayersType(); let promises = []; for (let i = 0; i < 10; i++) { let player = new Player(this.scene, { isCpu: this.options.isCpu }); const promise = player.clone() .then(() => { if (this.options.side === 'left') { player.setRotateY(90); } else { player.setRotateY(-90); } player.setType(types[i]); player.show(); this.players.push(player); }); promises.push(promise); } Promise.all(promises) .then(() => this.setStartPositions()); resolve(); }); }); }
setStartPositions() { const startPositions = this.getStartPositions(); this.players.forEach((item: Player, index: number) => { item.isRun = false; if (startPositions[index]) { item.setPositionX(startPositions[index].x); item.setPositionZ(startPositions[index].z); } }) } protected getStartPositions() { const halfFieldWidth = FIELD_WIDTH / 2; const halfFieldHeight = FIELD_HEIGHT / 2; if (this.options.side === 'left') { return [ { x: this.getRandomPosition(- halfFieldWidth * .6), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .1) }, { x: this.getRandomPosition(- halfFieldWidth * .6), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .4) }, { x: this.getRandomPosition(- halfFieldWidth * .6), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .7) }, { x: this.getRandomPosition(- halfFieldWidth * .6), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .9) }, { x: this.getRandomPosition(- halfFieldWidth * .4), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .1) }, { x: this.getRandomPosition(- halfFieldWidth * .4), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .4) }, { x: this.getRandomPosition(- halfFieldWidth * .4), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .7) }, { x: this.getRandomPosition(- halfFieldWidth * .4), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .9) }, { x: this.getRandomPosition(- halfFieldWidth * .2), z: 0 }, { x: 0, z: 0 } ]; } else { return [ { x: this.getRandomPosition(halfFieldWidth * .6), z: - halfFieldHeight + FIELD_HEIGHT * .1 }, { x: this.getRandomPosition(halfFieldWidth * .6), z: - halfFieldHeight + FIELD_HEIGHT * .4 }, { x: this.getRandomPosition(halfFieldWidth * .6), z: - halfFieldHeight + FIELD_HEIGHT * .7 }, { x: this.getRandomPosition(halfFieldWidth * .6), z: - halfFieldHeight + FIELD_HEIGHT * .9 }, { x: this.getRandomPosition(halfFieldWidth * .4), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .1) }, { x: this.getRandomPosition(halfFieldWidth * .4), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .4) }, { x: this.getRandomPosition(halfFieldWidth * .4), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .7) }, { x: this.getRandomPosition(halfFieldWidth * .4), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .9) }, { x: this.getRandomPosition(halfFieldWidth * .2), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .3) }, { x: this.getRandomPosition(halfFieldWidth * .2), z: this.getRandomPosition(- halfFieldHeight + FIELD_HEIGHT * .7) }, ]; } }
protected getRandomPosition(n: number, size?: number): number { size = size || 2; const min = n - size; const max = n + size; return Math.random() * (max - min) + min; } protected getRandomPositionX(x: number, size?: number) { let position = this.getRandomPosition(x, size); position = Math.min(position, FIELD_WIDTH / 2); position = Math.max(position, - FIELD_WIDTH / 2); return position; } protected getRandomPositionZ(z: number, size?: number) { let position = this.getRandomPosition(z, size); position = Math.min(position, FIELD_HEIGHT / 2); position = Math.max(position, - FIELD_HEIGHT / 2); return position; }
getNearestPlayer(point: FootballObject): Player { let min: number = Infinity, nearest: Player = null; this.players.forEach((item: Player) => { if (item !== point && item.isActive) { const distance = Utils.getDistance(item, point); if (distance < min) { min = distance; nearest = item; } } }); return nearest; } getNearestForwardPlayer(point: FootballObject): Player { let min: number = Infinity, nearest: Player = null; this.players.forEach((item: Player) => { if (item !== point && item.isActive && item.getPositionX() > point.getPositionX()) { const distance = Utils.getDistance(item, point); if (distance < min) { min = distance; nearest = item; } } }); return nearest || this.getNearestPlayer(point); }
static getDistance(obj1: FootballObject, obj2: FootballObject): number { if (obj1 && obj2) { const distanceX = obj1.getPositionX() - obj2.getPositionX(); const distanceZ = obj1.getPositionZ() - obj2.getPositionZ(); return Math.sqrt(distanceX * distanceX + distanceZ * distanceZ); } }
setStrategy(strategy: string) { const isLeft = this.options.side === 'left'; const RND_SIZE = 4; switch (strategy) { case 'defense': this.players .filter((item: Player) => item.getType() === PlayerType.FORWARD && item !== this.currentPlayer) .forEach((item: Player) => { item.moveTo(this.getRandomPositionX(0, RND_SIZE), this.getRandomPositionZ(item.getPositionZ(), RND_SIZE)); }); this.players .filter((item: Player) => item.getType() === PlayerType.MIDFIELDER && item !== this.currentPlayer) .forEach((item: Player) => { item.moveTo(this.getRandomPositionX(((isLeft ? - FIELD_WIDTH : FIELD_WIDTH) / 2) * .4, RND_SIZE), this.getRandomPositionZ(item.getPositionZ(), RND_SIZE)); }); this.players .filter((item: Player) => item.getType() === PlayerType.DEFENDER && item !== this.currentPlayer) .forEach((item: Player) => { item.moveTo(this.getRandomPositionX(((isLeft ? - FIELD_WIDTH : FIELD_WIDTH) / 2) * .6, RND_SIZE), this.getRandomPositionZ(item.getPositionZ(), RND_SIZE)); }); break; case 'attack': this.players .filter((item: Player) => item.getType() === PlayerType.FORWARD && item !== this.currentPlayer) .forEach((item: Player) => { item.moveTo(this.getRandomPositionX(((isLeft ? FIELD_WIDTH : - FIELD_WIDTH) / 2) * .7, RND_SIZE), this.getRandomPositionZ(item.getPositionZ(), RND_SIZE)); }); this.players .filter((item: Player) => item.getType() === PlayerType.MIDFIELDER && item !== this.currentPlayer) .forEach((item: Player) => { item.moveTo(this.getRandomPositionX(((isLeft ? FIELD_WIDTH : - FIELD_WIDTH) / 2) * .5, RND_SIZE), this.getRandomPositionZ(item.getPositionZ(), RND_SIZE)); }); this.players .filter((item: Player) => item.getType() === PlayerType.DEFENDER && item !== this.currentPlayer) .forEach((item: Player) => { item.moveTo(this.getRandomPositionX(0, RND_SIZE), this.getRandomPositionZ(item.getPositionZ(), RND_SIZE)); }); break; } }
Source: https://habr.com/ru/post/339028/