public static EntityTemplate Drone(AxialCoordinate position, string playerId) { // Calculate the world position based off the grid position. var worldPosition = HexUtils.GridToWorld(position); var entityTemplate = new EntityTemplate(); entityTemplate.AddComponent( new Drone.Snapshot { Owner = playerId, CommandQueue = new List <Command>() }, WorkerUtils.UnityGameLogic); entityTemplate.AddComponent( new Position.Snapshot(new Coordinates { X = worldPosition.x, Z = worldPosition.y }), WorkerUtils.UnityGameLogic); entityTemplate.AddComponent( new PlayerInventory.Snapshot(0, 0), WorkerUtils.UnityGameLogic); entityTemplate.AddComponent(new Metadata.Snapshot("Drone"), WorkerUtils.UnityGameLogic); entityTemplate.AddComponent(new Persistence.Snapshot(), WorkerUtils.UnityGameLogic); entityTemplate.SetReadAccess(WorkerUtils.AllWorkers); entityTemplate.SetComponentWriteAccess(EntityAcl.ComponentId, WorkerUtils.UnityGameLogic); return(entityTemplate); }
private void Update() { // TODO: Use a better source of pointer input than Input.mousePosition. var viewportPosition = Input.mousePosition; viewportPosition.z = _camera.transform.position.y; var worldPosition = _camera.ScreenToWorldPoint(viewportPosition); // Snap the cursor display to the cell the mouse is over. _cursorGridPosition = HexUtils.WorldToGrid(new Vector2(worldPosition.x, worldPosition.z)); worldPosition = HexUtils.GridToWorld(_cursorGridPosition); _cursor.transform.position = new Vector3(worldPosition.x, 0f, worldPosition.y); // TODO: Use a better source of input than Input. It would be nice to // use the EventSystem, but it's not clear how use it when clicking on // empty space. if (Input.GetMouseButtonDown(0) && _selectedDrone != null) { var command = new MoveToPosition { Target = _cursorGridPosition, }; AddCommandToQueue(CommandType.MoveToPosition, JsonUtility.ToJson(command), 5); } }
private static Snapshot CreateSnapshot(Arguments arguments) { var snapshot = new Snapshot(); AddPlayerSpawner(snapshot); AddSpawnController(snapshot); var halfWidth = arguments.WorldDimensions.x / 2f; var halfHeight = arguments.WorldDimensions.y / 2f; for (var i = 0; i < arguments.NumResourceNodes; i += 1) { // Generate random grid position that is within the real world bounds. // // TODO: Use a better algorithm for picking random grid coordinates. // We're currently picking random spots in a skewed rectangle, and // it would better to more evenly distrubte the nodes around the // center of the map. AxialCoordinate gridPos; Vector2 worldPos; do { gridPos = new AxialCoordinate( (int)Random.Range(-halfWidth, halfWidth), (int)Random.Range(-halfHeight, halfHeight)); worldPos = HexUtils.GridToWorld(gridPos); } while (Mathf.Abs(worldPos.x) >= halfWidth || Mathf.Abs(worldPos.y) >= halfHeight); var type = Random.value < 0.5f ? ResourceType.Coal : ResourceType.Copper; AddResourceNode(snapshot, gridPos, type); } return snapshot; }
private static void AddResourceNode(Snapshot snapshot, AxialCoordinate position, ResourceType type) { var template = new EntityTemplate(); var worldPos = HexUtils.GridToWorld(position); template.AddComponent(new Position.Snapshot(new Coordinates(worldPos.x, 0, worldPos.y)), WorkerUtils.UnityGameLogic); template.AddComponent( new Metadata.Snapshot { EntityType = "ResourceNode" }, WorkerUtils.UnityGameLogic); template.AddComponent(new Persistence.Snapshot(), WorkerUtils.UnityGameLogic); template.AddComponent(new ResourceNode.Snapshot(type, 100), WorkerUtils.UnityGameLogic); template.AddComponent(new GridPosition.Snapshot(position.ToGridCoordinate()), WorkerUtils.UnityGameLogic); template.SetReadAccess(WorkerUtils.AllWorkers); template.SetComponentWriteAccess(EntityAcl.ComponentId, WorkerUtils.UnityGameLogic); snapshot.AddEntity(template); }
private void Update() { // If the drone has a command it's actively working on, perform any work // related to that command. Otherwise, if there's a command in the queue, // make it the active command. if (_activeCommand.HasValue) { var command = _activeCommand.Value; switch (command.Type) { case CommandType.MoveToPosition: var moveToPosition = JsonUtility.FromJson <MoveToPosition>(command.Data); // Determine offset to the target position. var targetWorldPos = HexUtils.GridToWorld(moveToPosition.Target); var offset = targetWorldPos - _position; // Determine the distance to the target and the direction. var distance = offset.magnitude; var direction = offset.normalized; // If we're within a frame's distance from the target, snap to the // target and end movement. Otherwise, move towards the target. var maxMovement = Time.deltaTime * MOVE_SPEED; if (distance > maxMovement) { // Update the world position of the drone. _position = _position + maxMovement * direction; } else { // Snap to the target position and clear the active command. _position = targetWorldPos; _activeCommand = null; } break; case CommandType.HarvestResourceNode: var harvestResourceNode = JsonUtility.FromJson <HarvestResourceNode>(command.Data); if (!resourceCollectionTimer.HasValue) { resourceCollectionTimer = 0; } else if (resourceCollectionTimer.Value < 1f) { resourceCollectionTimer += Time.deltaTime; } else { resourceCollectionTimer = null; Entity targetEntity; if (_linkedEntity.Worker.TryGetEntity(new EntityId(harvestResourceNode.Target), out targetEntity)) { var entityManager = _linkedEntity.World.EntityManager; var resourceNodeComponent = entityManager.GetComponentData <ResourceNode.Component>(targetEntity); uint harvestedQuantity = System.Math.Min(1, resourceNodeComponent.Quantity); resourceNodeComponent.Quantity -= harvestedQuantity; entityManager.SetComponentData <ResourceNode.Component>(targetEntity, resourceNodeComponent); switch (resourceNodeComponent.Type) { case ResourceType.Coal: _inventory.Coal += harvestedQuantity; break; case ResourceType.Copper: _inventory.Copper += harvestedQuantity; break; } if (resourceNodeComponent.Quantity <= 0) { // Clear the active command. _activeCommand = null; } } else { Debug.Log($"Target resource node {harvestResourceNode.Target} doesn't exist, cancelling command"); // Clear the active command. _activeCommand = null; } } break; default: Debug.LogWarning($"Unable to perform unknown command {command.Type}, discarding active command"); // Discard the active command, _activeCommand = null; break; } } else if (_commandQueue.Count > 0) { _activeCommand = _commandQueue[0]; _commandQueue.RemoveAt(0); Debug.Log($"Making command {_activeCommand} active for drone {_linkedEntity.EntityId}"); } var worldPosition = new Vector3(_position.x, 0f, _position.y); transform.position = worldPosition + _linkedEntity.Worker.Origin; // Periodically send updates to components that are rate-limited by time. _timeToNextUpdate -= Time.deltaTime; if (_timeToNextUpdate < 0f || _droneWriter.Authority == Authority.AuthorityLossImminent) { // Check for updates to the position component. if (_timeToNextUpdate < 0f && !worldPosition.Equals(_positionWriter.Data.Coords)) { _positionWriter.SendUpdate(new Position.Update { Coords = new Coordinates(worldPosition.x, worldPosition.y, worldPosition.z), }); } // Check for updates to the inventory. if (_timeToNextUpdate < 0f && _inventory.IsDataDirty()) { _inventoryWriter.SendUpdate(new PlayerInventory.Update { Coal = _inventory.Coal, Copper = _inventory.Copper, }); _inventory.MarkDataClean(); } // Track drone updates. var droneUpdate = new Drone.Update(); var droneDirty = false; // TODO: Use regular == operator once SpatialOS generates the necessary code. if (!_activeCommand.Equals(_droneWriter.Data.ActiveCommand)) { droneUpdate.ActiveCommand = _activeCommand; droneDirty = true; } if (!_commandQueue.SequenceEqual(_droneWriter.Data.CommandQueue)) { droneUpdate.CommandQueue = _commandQueue; droneDirty = true; } if (droneDirty) { _droneWriter.SendUpdate(droneUpdate); } // Reset the time to the next update. _timeToNextUpdate = UPDATE_INTERVAL; } }