|
Dev Log
Sept 5, 2013 15:25:54 GMT -5
Post by JRooster76 on Sept 5, 2013 15:25:54 GMT -5
Found an excellent tutorial on Zelda-style health containers:
|
|
|
Dev Log
Sept 5, 2013 20:49:07 GMT -5
Post by JRooster76 on Sept 5, 2013 20:49:07 GMT -5
Not much to look at but here's what I got so far. I modified the code in the tutorial so that the hearts are placed on the top center of the screen. Next up is updating the heart container to reflect taking damage.
|
|
|
Dev Log
Sept 7, 2013 16:26:17 GMT -5
Post by JRooster76 on Sept 7, 2013 16:26:17 GMT -5
Here's what the heart containers look like when taking damage. Working on collision detection at the moment.
|
|
|
Dev Log
Sept 7, 2013 16:28:15 GMT -5
Post by JRooster76 on Sept 7, 2013 16:28:15 GMT -5
Here's the modified health meter code:
using UnityEngine; using System.Collections;
public class Health : MonoBehaviour {
public int startHealth; public int healthPerHeart;
public int maxHealth; private int currentHealth;
public Texture[] heartImages; public GUITexture heartGUI;
private ArrayList hearts = new ArrayList();
// Spacing: public int maxHeartsPerRow = 10; private float spacingX; private float spacingY;
void Start() { spacingX = heartGUI.pixelInset.width; spacingY = -heartGUI.pixelInset.height; ClampHealth(); currentHealth = startHealth; AddHearts(Mathf.CeilToInt(maxHealth / (float)healthPerHeart)); }
private void ClampHealth() { maxHealth = Mathf.Clamp(maxHealth, 1, 100); currentHealth = Mathf.Clamp(currentHealth, 0, maxHealth); startHealth = Mathf.Clamp(startHealth, 0, maxHealth); healthPerHeart = Mathf.Clamp(healthPerHeart, 1, maxHealth); }
public void AddHearts(int n) { for (int i = 0; i < n; i++) { Transform newHeart = ((GameObject)Instantiate(heartGUI.gameObject, this.transform.position, Quaternion.identity)).transform; // Creates a new heart newHeart.parent = transform;
int y = hearts.Count / maxHeartsPerRow; int x = hearts.Count - y * maxHeartsPerRow;
newHeart.GetComponent<GUITexture>().pixelInset = new Rect(x * spacingX, y * spacingY, spacingX, -spacingY); newHeart.GetComponent<GUITexture>().texture = heartImages[0]; hearts.Add(newHeart);
} CenterAlign(n * spacingX); UpdateHearts(); }
private void CenterAlign(float totalWidth) { //Center on screen float screenWidth = Screen.width; Vector3 currentPosition = this.transform.position; float centerX = ((currentPosition.x * screenWidth) - (totalWidth * 0.5f)) / screenWidth; this.transform.position = new Vector3(centerX, currentPosition.y); }
public void ModifyHealth(int amount) { currentHealth += amount; ClampHealth(); UpdateHearts(); }
void UpdateHearts() { bool restAreEmpty = false; int i = 0;
foreach (Transform heart in hearts) {
if (restAreEmpty || currentHealth == 0) { heart.guiTexture.texture = heartImages[(int)HealthImage.Empty]; // heart is empty } else { i += 1; // current iteration if (currentHealth >= i * healthPerHeart) { heart.guiTexture.texture = heartImages[(int)HealthImage.Full]; // health of current heart is full } else { int currentHeartHealth = currentHealth % healthPerHeart; float healthPerImage = healthPerHeart / (heartImages.Length - 2); // how much health is there per image int imageIndex = Mathf.CeilToInt(currentHeartHealth / healthPerImage);
heart.guiTexture.texture = heartImages[imageIndex]; restAreEmpty = true; } }
} } }
public enum HealthImage { Empty = 0, Quarter = 1, Half = 2, ThreeQuarter = 3, Full = 4 }
|
|
redquill
Administrator
BLU (r)Mage
Where do you live, Monster?
Posts: 186
|
Dev Log
Sept 8, 2013 19:35:45 GMT -5
Post by redquill on Sept 8, 2013 19:35:45 GMT -5
The code is far over my head; I can't believe I listened to the whole thing. Seeing the graphic has me thinking about how we're going to display armour and such as well. HUD in general is something I'll keep in the back of my mind this week. Keep up the good work!
|
|
|
Dev Log
Sept 8, 2013 21:17:31 GMT -5
Post by JRooster76 on Sept 8, 2013 21:17:31 GMT -5
Thanks man! I got collision detection working somewhat. I can tell if a player been hit in the front, sides (though not which side), or back. That info will be useful for hit animations, and for characters that can block attacks.
|
|
|
Dev Log
Sept 17, 2013 15:13:27 GMT -5
Post by JRooster76 on Sept 17, 2013 15:13:27 GMT -5
So I've been working on locking and found it to be a bit trickier than I expected. The issue is how Unity handles colliders. In Unity, you can put a game object in its own collision layer then designate which layers can collide with one another. For example, I've setup 3 layers: player, ally, and enemy. Player can walk through allies but cannot walk through enemies. The problem is that when you tell Unity to ignore a layer it also turns off collision triggers. A trigger is an invisible volume that detects other colliders. When collider enters its space, an event is raised so that you can react to it. Think of how doors work in FP. There is a trigger on the door that checks whether the player is an ally or enemy. Depending on which, the open door animation plays. Triggers are essential because they tell me when an ally or enemy comes within range.
So instead of turning off the collision at the layer level, I'm telling Unity to ignore collision at the object level. For some reason, ignoring collision this way does not turn off triggers. The problem with this approach is that I have to tell Unity to ignore every ally object individually. If there's a respawn, then I have to account for that as well because Unity treats it as a new object.
What I plan to do is to check at the time of collision if an object is an ally. I'll turn off collision for that object, but triggers will still work. Not sure what happens memory-wise after an ally object is destroyed but I'm pretty sure Unity handles the clean up. I could also have a script that keeps track of respawns and turn it off as soon as an ally object is created.
Not sure yet how this will work during multiplayer games. From player A's point of view, player B is an ally. From player B's point of view, player A is an ally. I don't know if Unity can change the layers of each player depending on which point of view the game is being played. I'm pretty sure there's a way otherwise you'd never be able to make a multiplayer game.
The other tricky part is switching between ally and enemy locks. Since is character driven, I can't write a generic targeting script. I'll probably have to have 2 versions of the targeting script: one for allies and one for enemies. Oh, there'll probably a third one for scene objects (mask machines, ores, trees, etc.). Crap, I have to figure out a way to generalize this. Perhaps a generic script with a some sort of property telling it what it can lock on to (allies, enemies, objects)...
|
|
redquill
Administrator
BLU (r)Mage
Where do you live, Monster?
Posts: 186
|
Dev Log
Sept 17, 2013 19:01:55 GMT -5
Post by redquill on Sept 17, 2013 19:01:55 GMT -5
It sounds like this would be a common problem. You might be better served talking to CULD or finding a tutorial than doing something this complex.
|
|
|
Dev Log
Sept 18, 2013 11:38:22 GMT -5
Post by JRooster76 on Sept 18, 2013 11:38:22 GMT -5
Yes, I was curious about it so I did do a quick search on multiplayer games in Unity. In brief, there are 2 ways of handling multiplayer games: authoritative server and non-authoritative server. In an authoritative server, all objects are created and maintained in a central server. Clients (players) only send and receive updates. In a non-authoritative server, clients own the objects. Updates are sent to the central server and all other clients are updated accordingly. There are pro's and con's for each method. In the end, we'll probably have to do a hybrid approach. Some things the server will handle, others things the clients will handle it.
This is something we need not worry about at the moment since we will be focusing on the single player campaign. It was just a thought that entered my head while I was writing.
|
|
redquill
Administrator
BLU (r)Mage
Where do you live, Monster?
Posts: 186
|
Dev Log
Sept 18, 2013 13:51:38 GMT -5
Post by redquill on Sept 18, 2013 13:51:38 GMT -5
Foresight is always good. While you might not need to act on it now, be sure to keep it in mind. Do you know what sort FP used, or was is not a concern since Unity was the engine?
For myself, I did some scouting on Steam. Unity should work fine with their engine; I've seen published games that have the Unity logo on the splash screen.
|
|
|
Dev Log
Sept 19, 2013 8:36:46 GMT -5
Post by JRooster76 on Sept 19, 2013 8:36:46 GMT -5
I don't know for sure but if I had to make an educated guess I'd say that it uses a combination of the two. However, the way FP handles matchmaking is different from the way we will be doing it. FP designates a player as the host. We will most likely use a central server (Kongregate, Photon, etc.) as the host. It's just a matter of deciding which parts of the game should be handled at the server vs. client.
On another note, I'm close to finishing locking. Probably another night or 2 of coding, though I might leave it for the weekend.
|
|
|
Dev Log
Sept 20, 2013 22:23:26 GMT -5
Post by JRooster76 on Sept 20, 2013 22:23:26 GMT -5
I've been able to get my character to lock on to another object based on proximity, however, I need to add more logic to make locking behave more like FP. I believe that the direction the player is facing has an influence in priority as far as which object they lock onto. So if 2 enemies are at the exact same distance from the player, yet one of them is in front, that front facing enemy will be chosen over the one behind or to the side. If there are no targets in front of the player, then it will pick the closest one.
I may also have to make individual targeting scripts per class, as there could other factors that influence lock priority such as health of an ally. The priests in FP tend to lock on to an ally that has the least health first. We may want to do the same. Workers tend to ignore trees and ore when an enemy draws near. TBH, I find that to be annoying. There are times when I rather focus on the resource than fight the enemy. But I suppose that if the opposite was true and I needed to take care of an nearby enemy, I would be pissed off if the worker was constantly locking on to the resources.
Hmmm, I suppose we could make it so that if the worker was using his/her primary weapon then the priority would be on resources. If the worker used its secondary weapon, the priority would be on enemies. This would also work even if the worker hadn't been upgraded. Pressing the secondary weapon button would cause the worker to use the primary weapon but the priority would change.
|
|
|
Dev Log
Sept 21, 2013 10:21:46 GMT -5
Post by JRooster76 on Sept 21, 2013 10:21:46 GMT -5
Basic targeting pretty much done. I need to tweak a couple of things but the code works in general. Here's the code:
using UnityEngine; using System.Collections; using System.Collections.Generic;
public class Targeting : MonoBehaviour { private GameObject currentTarget; private PlatformInputController inputController;
public float range = 10f; public LayerMask layer;
// Use this for initialization void Start () { inputController = GetComponent<PlatformInputController>(); } // Update is called once per frame void Update() { //Lock button pressed. if (Input.GetButtonDown("Lock")) { //Find the closest target. currentTarget = GetClosestTarget(range, layer); if (currentTarget != null) { Debug.Log(currentTarget.name); } }
//Lock button released. if (Input.GetButtonUp("Lock")) { currentTarget.renderer.material.color = Color.white; currentTarget = null; inputController.autoRotate = true; }
//Lock button held. if (Input.GetButton("Lock")) { if (currentTarget != null) { currentTarget.renderer.material.color = Color.red; inputController.autoRotate = false; //Turn off auto-rotation while locking. transform.LookAt(currentTarget.transform); //Rotate player towards target. } } }
GameObject GetClosestTarget(float radius, int layer) { GameObject closestTarget = null; float distance = radius; float currentDistance = 0f; //TODO: Need to optimize search as there could be thousands of gameobjects in a scene. GameObject[] targets = GameObject.FindObjectsOfType(typeof(GameObject)) as GameObject[];
foreach (GameObject target in targets) { if ((layer & (1 << (target.layer))) != 0) { Vector3 forward = transform.TransformDirection(Vector3.forward); Vector3 toOther = target.transform.position - transform.position; //The priority variable gives more weight to targets in front of player. float priority = Mathf.Clamp(Vector3.Dot(forward.normalized, toOther.normalized), 0f, 1f); currentDistance = Vector3.Distance(target.transform.position, this.transform.position) - priority; if (currentDistance < distance) { closestTarget = target; distance = currentDistance; } } } return closestTarget; } }
|
|
|
Dev Log
Oct 14, 2013 8:37:38 GMT -5
Post by JRooster76 on Oct 14, 2013 8:37:38 GMT -5
|
|
|
Dev Log
Oct 20, 2013 18:51:46 GMT -5
Post by JRooster76 on Oct 20, 2013 18:51:46 GMT -5
Been doing more research into 3D modeling apps. Found some good ones that even a novice like myself can easily can get things going.
For modeling: Silo 2 For rigging: Daz3D 4.6 For animation: iClone 5
Still need to find something for textures and materials. Although Blender can do all of the above (and then some), it comes at a rather steep learning curve. The interface is just not very noob friendly.
|
|