Skip to content

Commit

Permalink
Part 22
Browse files Browse the repository at this point in the history
  • Loading branch information
stormtek committed Nov 22, 2014
1 parent 6718b64 commit 8202e98
Show file tree
Hide file tree
Showing 29 changed files with 240 additions and 16 deletions.
2 changes: 2 additions & 0 deletions RTS Tutorial/Assembly-CSharp-vs.csproj
Expand Up @@ -78,6 +78,8 @@
<Compile Include="Assets\WorldObject\Building\Building.cs" />
<Compile Include="Assets\WorldObject\Building\Buildings.cs" />
<Compile Include="Assets\WorldObject\Building\Refinery\Refinery.cs" />
<Compile Include="Assets\WorldObject\Building\Turret\Turret.cs" />
<Compile Include="Assets\WorldObject\Building\Turret\TurretProjectile.cs" />
<Compile Include="Assets\WorldObject\Building\WarFactory\WarFactory.cs" />
<Compile Include="Assets\WorldObject\Building\Wonder\Wonder.cs" />
<Compile Include="Assets\WorldObject\Projectile.cs" />
Expand Down
2 changes: 2 additions & 0 deletions RTS Tutorial/Assembly-CSharp.csproj
Expand Up @@ -78,6 +78,8 @@
<Compile Include="Assets\WorldObject\Building\Building.cs" />
<Compile Include="Assets\WorldObject\Building\Buildings.cs" />
<Compile Include="Assets\WorldObject\Building\Refinery\Refinery.cs" />
<Compile Include="Assets\WorldObject\Building\Turret\Turret.cs" />
<Compile Include="Assets\WorldObject\Building\Turret\TurretProjectile.cs" />
<Compile Include="Assets\WorldObject\Building\WarFactory\WarFactory.cs" />
<Compile Include="Assets\WorldObject\Building\Wonder\Wonder.cs" />
<Compile Include="Assets\WorldObject\Projectile.cs" />
Expand Down
Binary file modified RTS Tutorial/Assembly-CSharp.pidb
Binary file not shown.
Binary file modified RTS Tutorial/Assets/Map.unity
Binary file not shown.
Binary file modified RTS Tutorial/Assets/Menu/MainMenu.unity
Binary file not shown.
1 change: 1 addition & 0 deletions RTS Tutorial/Assets/Player/Player.cs
Expand Up @@ -98,6 +98,7 @@ public class Player : MonoBehaviour {
tempBuilding.ObjectId = ResourceManager.GetNewObjectId();
tempCreator = creator;
findingPlacement = true;
tempBuilding.hitPoints = 0;
tempBuilding.SetTransparentMaterial(notAllowedMaterial, true);
tempBuilding.SetColliders(false);
tempBuilding.SetPlayingArea(playingArea);
Expand Down
31 changes: 31 additions & 0 deletions RTS Tutorial/Assets/RTS/WorkManager.cs
Expand Up @@ -66,5 +66,36 @@ public static class WorkManager {
default: return ResourceType.Unknown; break;
}
}

public static List<WorldObject> FindNearbyObjects(Vector3 position, float range) {
Collider[] hitColliders = Physics.OverlapSphere(position, range);
HashSet<int> nearbyObjectIds = new HashSet<int>();
List<WorldObject> nearbyObjects = new List<WorldObject>();
for(int i = 0; i < hitColliders.Length; i++) {
Transform parent = hitColliders[i].transform.parent;
if(parent) {
WorldObject parentObject = parent.GetComponent<WorldObject>();
if(parentObject && !nearbyObjectIds.Contains(parentObject.ObjectId)) {
nearbyObjectIds.Add(parentObject.ObjectId);
nearbyObjects.Add(parentObject);
}
}
}
return nearbyObjects;
}

public static WorldObject FindNearestWorldObjectInListToPosition(List<WorldObject> objects, Vector3 position) {
if(objects == null || objects.Count == 0) return null;
WorldObject nearestObject = objects[0];
float distanceToNearestObject = Vector3.Distance(position, nearestObject.transform.position);
for(int i = 1; i < objects.Count; i++) {
float distanceToObject = Vector3.Distance(position, objects[i].transform.position);
if(distanceToObject < distanceToNearestObject) {
distanceToNearestObject = distanceToObject;
nearestObject = objects[i];
}
}
return nearestObject;
}
}
}
15 changes: 10 additions & 5 deletions RTS Tutorial/Assets/Resources/LevelLoader.cs
Expand Up @@ -31,6 +31,7 @@ public class LevelLoader : MonoBehaviour {
PlayerManager.SelectPlayer(player.username, 0);
}
}
SetObjectIds();
}
}
}
Expand All @@ -40,11 +41,7 @@ public class LevelLoader : MonoBehaviour {
if(ResourceManager.LevelName != null && ResourceManager.LevelName != "") {
LoadManager.LoadGame(ResourceManager.LevelName);
} else {
WorldObject[] worldObjects = GameObject.FindObjectsOfType(typeof(WorldObject)) as WorldObject[];
foreach(WorldObject worldObject in worldObjects) {
worldObject.ObjectId = nextObjectId++;
if(nextObjectId >= int.MaxValue) nextObjectId = 0;
}
SetObjectIds();
}
Time.timeScale = 1.0f;
ResourceManager.MenuOpen = false;
Expand All @@ -56,4 +53,12 @@ public class LevelLoader : MonoBehaviour {
if(nextObjectId >= int.MaxValue) nextObjectId = 0;
return nextObjectId;
}

private void SetObjectIds() {
WorldObject[] worldObjects = GameObject.FindObjectsOfType(typeof(WorldObject)) as WorldObject[];
foreach(WorldObject worldObject in worldObjects) {
worldObject.ObjectId = nextObjectId++;
if(nextObjectId >= int.MaxValue) nextObjectId = 0;
}
}
}
4 changes: 4 additions & 0 deletions RTS Tutorial/Assets/WorldObject/Building/Refinery/Refinery.cs
Expand Up @@ -11,4 +11,8 @@ public class Refinery : Building {
base.PerformAction(actionToPerform);
CreateUnit(actionToPerform);
}

protected override bool ShouldMakeDecision () {
return false;
}
}
48 changes: 48 additions & 0 deletions RTS Tutorial/Assets/WorldObject/Building/Turret/Turret.cs
@@ -0,0 +1,48 @@
using UnityEngine;
using System.Collections;
using RTS;

public class Turret : Building {

private Quaternion aimRotation;

protected override void Start () {
base.Start ();
detectionRange = weaponRange;
}

protected override void Update () {
base.Update();
if(aiming) {
transform.rotation = Quaternion.RotateTowards(transform.rotation, aimRotation, weaponAimSpeed);
CalculateBounds();
//sometimes it gets stuck exactly 180 degrees out in the calculation and does nothing, this check fixes that
Quaternion inverseAimRotation = new Quaternion(-aimRotation.x, -aimRotation.y, -aimRotation.z, -aimRotation.w);
if(transform.rotation == aimRotation || transform.rotation == inverseAimRotation) {
aiming = false;
}
}
}

public override bool CanAttack() {
if(UnderConstruction() || hitPoints == 0) return false;
return true;
}

protected override void UseWeapon () {
base.UseWeapon();
Vector3 spawnPoint = transform.position;
spawnPoint.x += (2.6f * transform.forward.x);
spawnPoint.y += 1.0f;
spawnPoint.z += (2.6f * transform.forward.z);
GameObject gameObject = (GameObject)Instantiate(ResourceManager.GetWorldObject("TurretProjectile"), spawnPoint, transform.rotation);
Projectile projectile = gameObject.GetComponentInChildren<Projectile>();
projectile.SetRange(0.9f * weaponRange);
projectile.SetTarget(target);
}

protected override void AimAtTarget () {
base.AimAtTarget();
aimRotation = Quaternion.LookRotation (target.transform.position - transform.position);
}
}
Binary file not shown.
@@ -0,0 +1,4 @@
using UnityEngine;
using System.Collections;

public class TurretProjectile : Projectile {}
Binary file not shown.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Expand Up @@ -11,4 +11,8 @@ public class WarFactory : Building {
base.PerformAction(actionToPerform);
CreateUnit(actionToPerform);
}

protected override bool ShouldMakeDecision () {
return false;
}
}
4 changes: 3 additions & 1 deletion RTS Tutorial/Assets/WorldObject/Building/Wonder/Wonder.cs
Expand Up @@ -2,5 +2,7 @@
using System.Collections;

public class Wonder : Building {
//nothing special to specify
protected override bool ShouldMakeDecision () {
return false;
}
}
4 changes: 4 additions & 0 deletions RTS Tutorial/Assets/WorldObject/Resource/Resource.cs
Expand Up @@ -52,4 +52,8 @@ public class Resource : WorldObject {
default: break;
}
}

protected override bool ShouldMakeDecision () {
return false;
}
}
41 changes: 39 additions & 2 deletions RTS Tutorial/Assets/WorldObject/Unit/Harvester/Harvester.cs
Expand Up @@ -63,7 +63,7 @@ public class Harvester : Unit {
foreach(Arms arm in arms) arm.renderer.enabled = true;
if(harvesting) {
Collect();
if(currentLoad >= capacity || resourceDeposit.isEmpty()) {
if(currentLoad >= capacity) {
//make sure that we have a whole number to avoid bugs
//caused by floating point numbers
currentLoad = Mathf.Floor(currentLoad);
Expand Down Expand Up @@ -171,11 +171,18 @@ public class Harvester : Unit {
float collect = collectionAmount * Time.deltaTime;
//make sure that the harvester cannot collect more than it can carry
if(currentLoad + collect > capacity) collect = capacity - currentLoad;
resourceDeposit.Remove(collect);
if(resourceDeposit.isEmpty()) {
Arms[] arms = GetComponentsInChildren<Arms>();
foreach(Arms arm in arms) arm.renderer.enabled = false;
DecideWhatToDo();
} else {
resourceDeposit.Remove(collect);
}
currentLoad += collect;
}

private void Deposit() {
currentLoad = Mathf.Floor(currentLoad);
if(audioElement != null && Time.timeScale > 0) audioElement.Play(emptyHarvestSound);
currentDeposit += depositAmount * Time.deltaTime;
int deposit = Mathf.FloorToInt(currentDeposit);
Expand All @@ -200,4 +207,34 @@ public class Harvester : Unit {
Texture2D resourceBar = ResourceManager.GetResourceHealthBar(harvestType);
if(resourceBar) GUI.DrawTexture(new Rect(leftPos, topPos, width, height), resourceBar);
}

protected override bool ShouldMakeDecision () {
if(harvesting || emptying) return false;
return base.ShouldMakeDecision();
}

protected override void DecideWhatToDo () {
base.DecideWhatToDo ();
List<WorldObject> resources = new List<WorldObject>();
foreach(WorldObject nearbyObject in nearbyObjects) {
Resource resource = nearbyObject.GetComponent<Resource>();
if(resource && !resource.isEmpty()) resources.Add(nearbyObject);
}
WorldObject nearestObject = WorkManager.FindNearestWorldObjectInListToPosition(resources, transform.position);
if(nearestObject) {
Resource closestResource = nearestObject.GetComponent<Resource>();
if(closestResource) StartHarvest(closestResource);
} else if(harvesting) {
harvesting = false;
if(currentLoad > 0.0f) {
//make sure that we have a whole number to avoid bugs
//caused by floating point numbers
currentLoad = Mathf.Floor(currentLoad);
emptying = true;
Arms[] arms = GetComponentsInChildren<Arms>();
foreach(Arms arm in arms) arm.renderer.enabled = false;
StartMove (resourceStore.transform.position, resourceStore.gameObject);
}
}
}
}
5 changes: 5 additions & 0 deletions RTS Tutorial/Assets/WorldObject/Unit/Unit.cs
Expand Up @@ -134,6 +134,11 @@ public class Unit : WorldObject {
}
}

protected override bool ShouldMakeDecision () {
if(moving || rotating) return false;
return base.ShouldMakeDecision();
}

/* Private worker methods */

private void TurnToTarget() {
Expand Down
22 changes: 21 additions & 1 deletion RTS Tutorial/Assets/WorldObject/Unit/Worker/Worker.cs
Expand Up @@ -18,7 +18,7 @@ public class Worker : Unit {

protected override void Start () {
base.Start();
actions = new string[] {"Refinery", "WarFactory", "Wonder"};
actions = new string[] {"Refinery", "WarFactory", "Wonder", "Turret"};
if(player && loadedSavedValues && loadedProjectId >= 0) {
WorldObject obj = player.GetObjectForId(loadedProjectId);
if(obj.GetType().IsSubclassOf(typeof(Building))) currentProject = (Building)obj;
Expand Down Expand Up @@ -106,6 +106,26 @@ public class Worker : Unit {
}
}

protected override bool ShouldMakeDecision () {
if(building) return false;
return base.ShouldMakeDecision();
}

protected override void DecideWhatToDo () {
base.DecideWhatToDo ();
List<WorldObject> buildings = new List<WorldObject>();
foreach(WorldObject nearbyObject in nearbyObjects) {
if(nearbyObject.GetPlayer() != player) continue;
Building nearbyBuilding = nearbyObject.GetComponent<Building>();
if(nearbyBuilding && nearbyBuilding.UnderConstruction()) buildings.Add(nearbyObject);
}
WorldObject nearestObject = WorkManager.FindNearestWorldObjectInListToPosition(buildings, transform.position);
if(nearestObject) {
Building closestBuilding = nearestObject.GetComponent<Building>();
if(closestBuilding) SetBuilding(closestBuilding);
}
}

/*** Private Methods ***/

private void CreateBuilding(string buildingName) {
Expand Down
47 changes: 45 additions & 2 deletions RTS Tutorial/Assets/WorldObject/WorldObject.cs
Expand Up @@ -9,7 +9,7 @@ public class WorldObject : MonoBehaviour {
public string objectName = "WorldObject";
public Texture2D buildImage;
public int cost = 100, sellValue = 10, hitPoints = 100, maxHitPoints = 100;
public float weaponRange = 10.0f, weaponRechargeTime = 1.0f, weaponAimSpeed = 1.0f;
public float weaponRange = 10.0f, weaponRechargeTime = 1.0f, weaponAimSpeed = 1.0f, detectionRange = 20.0f;
public AudioClip attackSound, selectSound, useWeaponSound;
public float attackVolume = 1.0f, selectVolume = 1.0f, useWeaponVolume = 1.0f;

Expand All @@ -25,11 +25,15 @@ public class WorldObject : MonoBehaviour {
protected bool attacking = false, movingIntoPosition = false, aiming = false;
protected bool loadedSavedValues = false;
protected AudioElement audioElement;
protected List<WorldObject> nearbyObjects;

//Private variables
private List<Material> oldMaterials = new List<Material>();
private float currentWeaponChargeTime;
private int loadedTargetId = -1;
//we want to restrict how many decisions are made to help with game performance
//the default time at the moment is a tenth of a second
private float timeSinceLastDecision = 0.0f, timeBetweenDecisions = 0.1f;

public int ObjectId { get; set; }

Expand Down Expand Up @@ -72,20 +76,59 @@ public class WorldObject : MonoBehaviour {
}

protected virtual void Update () {
if(ShouldMakeDecision()) DecideWhatToDo();
currentWeaponChargeTime += Time.deltaTime;
if(attacking && !movingIntoPosition && !aiming) PerformAttack();
}

protected virtual void OnGUI() {
if(currentlySelected && !ResourceManager.MenuOpen) DrawSelection();
}


/**
* A child class should only determine other conditions under which a decision should
* not be made. This could be 'harvesting' for a harvester, for example. Alternatively,
* an object that never has to make decisions could just return false.
*/
protected virtual bool ShouldMakeDecision() {
if(!attacking && !movingIntoPosition && !aiming) {
//we are not doing anything at the moment
if(timeSinceLastDecision > timeBetweenDecisions) {
timeSinceLastDecision = 0.0f;
return true;
}
timeSinceLastDecision += Time.deltaTime;
}
return false;
}

protected virtual void DecideWhatToDo() {
//determine what should be done by the world object at the current point in time
//Debug.Log("make decision for " + ObjectId + ": " + objectName + ", controlled by " + (player == null ? "no one" : player.username));
Vector3 currentPosition = transform.position;
nearbyObjects = WorkManager.FindNearbyObjects(currentPosition, detectionRange);
if(CanAttack()) {
List<WorldObject> enemyObjects = new List<WorldObject>();
foreach(WorldObject nearbyObject in nearbyObjects) {
Resource resource = nearbyObject.GetComponent<Resource>();
if(resource) continue;
if(nearbyObject.GetPlayer() != player) enemyObjects.Add(nearbyObject);
}
WorldObject closestObject = WorkManager.FindNearestWorldObjectInListToPosition(enemyObjects, currentPosition);
if(closestObject) BeginAttack(closestObject);
}
}

/*** Public methods ***/

public void SetPlayer() {
player = transform.root.GetComponentInChildren<Player>();
}

public Player GetPlayer() {
return player;
}

public virtual void SetSelection(bool selected, Rect playingArea) {
currentlySelected = selected;
if(selected) {
Expand Down
Binary file modified RTS Tutorial/Library/ScriptAssemblies/Assembly-CSharp.dll
Binary file not shown.
Binary file modified RTS Tutorial/Library/ScriptAssemblies/Assembly-CSharp.dll.mdb
Binary file not shown.
Binary file modified RTS Tutorial/Library/assetDatabase3
Binary file not shown.
Binary file modified RTS Tutorial/Library/guidmapper
Binary file not shown.
Binary file modified RTS Tutorial/Library/metadata/b2/b28c4dc01ee837c439f36a14b80f574e
Binary file not shown.

0 comments on commit 8202e98

Please sign in to comment.