[QUOTE=Over-Run;43368081]So I'm trying to implement the Object Pool design pattern in Unity.
Right now I have this class called ObjectPool
[/QUOTE]
Generally people will make the camera follow a game object, is this what you mean?
Also, not related to your problem but I created a generic object pool. For stuff like this I think it's good to come up with something generic that you can reuse with whatever.
Though I've never used it with Unity you could easily port it. It's super simple.
ObjectPool.cs
[code]
using System.Collections.Generic;
namespace Client
{
class ObjectPool<T> where T : IPoolable, new()
{
private List<T> objects = new List<T>();
public ObjectPool(int initialSpawn)
{
//Create an initial amount.
for(int i=0;i<initialSpawn;i++)
{
T obj = new T();
objects.Add(obj);
}
}
public T GetObject()
{
foreach (T obj in objects)
{
if (obj.Free)
{
obj.UnPool();
return obj;
}
}
//No free objects, spawn a new one.
T newObj = new T();
newObj.UnPool();
objects.Add(newObj);
return newObj;
}
}
}
[/code]
IPoolable.cs
[code]
namespace Client
{
interface IPoolable
{
void Pool();
void UnPool();
bool Free { get; set; }
}
static class PoolableExtension
{
public static void Pool(this IPoolable ext)
{
ext.Pool();
ext.Free = true;
}
public static void UnPool(this IPoolable ext)
{
ext.UnPool();
ext.Free = false;
}
}
}
[/code]
[QUOTE=Over-Run;43368081]And I created a sphere object that when left click is pressed, fires. However, the sphere keeps on shooting from some random point in the map. I was hoping to have it fire from in front of the camera. How can I make the spheres position stay updated with the camera?
Thanks[/QUOTE]
When you instantiate the objects, where are they located on the scene?
Also when you left click, what you did was only activate the objects. To achieve what you wanted, you need to move the object's position to wherever you wanted when you activate it.
[QUOTE=reevezy67;43368550]Generally people will make the camera follow a game object, is this what you mean?
Also, not related to your problem but I created a generic object pool. For stuff like this I think it's good to come up with something generic that you can reuse with whatever.
Though I've never used it with Unity you could easily port it. It's super simple.
ObjectPool.cs
-Code-
IPoolable.cs
-Code-[/QUOTE]To be honest, this is more of an object manager than an object pool.
I'd use something like this, which also is thread safe (if you manage the objects in a thread safe way)
[code]
public class ObjectPool<TObj> where TObj: class, new()
{
private ConcurrentQueue<TObj> _pool = new ConcurrentQueue<TObj>();
private int _maxObjects = 1000;
public void Recycle(TObj obj)
{
if(_pool.Count() < _maxObjects)
_pool.Enqueue(obj);
else
_obj = null;
}
public void GetObject()
{
TObj obj;
if(!_pool.TryDequeue(out obj))
obj = new TObj();
return obj;
}
}
[/code]
When I made the object in the scene I dragged the sphere to where my character is however it still spawns elsewhere when the left mouse is clicked. Ideally I would like to make it so when you press 1,2,3 or 4 it will change to different objects such as a square or circle or cylinder that will be fired . What I would be a good example use for the object pool?
Bullets are an example of using object pool. Bullets in most games typically live for less than 2 seconds. If you create a new bullet every single time a player [b]shoots*[/b], Unity's garbage collector will have more work to do. You create a new bullet, 2 seconds later it dies and "marked" for deletion. Repeat this how many times you shoot.
Lets say a plasma gattling gun with a fire rate of 20, in 5 seconds you'll create 100 bullets. 100 new objects created in duration of 5 seconds, each of them lives for around 2 seconds, and then thrown away, never to be seen again. Wasteful.
With object pooling, you create a pool of bullets. How many to create? Calculate it. If the bullet will be alive at max 2 seconds, and the weapon has a fire rate of 10, you need at least 20 bullets to pool. If you pool less than that (lets say 10), when you're shooting your 11th bullet, your first bullet (which is still alive) will be recycled instead. You don't want that to happen. Maybe in 0.1 second the first bullet will hit an enemy, but because you recycled it, it resets its position and lifetime.
*I am talking about projectile-based weapons (e.g. rocket launcher, plasma gun, arrows), not hitscan (raycast based)
[QUOTE=Over-Run;43392389]When I made the object in the scene I dragged the sphere to where my character is however it still spawns elsewhere when the left mouse is clicked.[/QUOTE]
Reset the position of the object when you left-click, in your case, the position is in front of the character. If your character is at (0,0,0) and your object is at (100,0,0), if you don't reset the object's position, it will still be at (100,0,0). Assign the value of your character's position to the object's position when you left click. Something like:
[code]
// THIS WON'T WORK AS IS
if(Input.GetButtonDown("Fire1")) // If the fire button (left mouse button) is pressed on this frame
{
//Your object pool selection loop or something here
object.transform.position = character.transform.position; // Reset the position
object.transform.rotation = character.transform.rotation; // Reset the orientation
object.SetActive(true); // Set the object to active
}
[/code]
I want a damn sandbox...
[img]https://dl.dropboxusercontent.com/u/251205348/Captura%20de%20pantalla%202014-01-02%2017.13.25.png[/img]
[img]https://dl.dropboxusercontent.com/u/251205348/Captura%20de%20pantalla%202014-01-02%2018.59.02.png[/img]
Yay, looking neat...
*checks the status data* 500 draw calls? time for optimize...350 draw calls...
Okay, i will look for already created worlds!
Thanks secondus for the reply there, that makes some sense to me.
However I'm pretty new to Unity and all and I'm not sure how to do the character.transform part? How do I access the character? I'm using a first person controller thing to use the camera.
EDIT
Here is a link to the Unity Answers section with some code
[URL]http://answers.unity3d.com/questions/607963/object-pool-shooting-not-working.html[/URL]
-snip-
fixed
[editline]edit[/editline]
[QUOTE=gonzalolog;43393903]I want a damn sandbox...
Yay, looking neat...
*checks the status data* 500 draw calls? time for optimize...350 draw calls...
Okay, i will look for already created worlds![/QUOTE]
That looks really cool. What's it gonna be?
[editline]edit[/editline]
Holy shit, having the game view on another monitor is amazing for making levels.
[QUOTE=Pelf;43394439]-snip-
fixed
[editline]edit[/editline]
That looks really cool. What's it gonna be?
[editline]edit[/editline]
Holy shit, having the game view on another monitor is amazing for making levels.[/QUOTE]
is funny but i don't have idea if it'll be a world editor lol
I'm very inspired on the drag and push editor of portal 2
[QUOTE=Over-Run;43394412]Thanks secondus for the reply there, that makes some sense to me.
However I'm pretty new to Unity and all and I'm not sure how to do the character.transform part? How do I access the character? I'm using a first person controller thing to use the camera.[/QUOTE]
All scripts that can be added to GameObject inherits from [url=https://docs.unity3d.com/Documentation/ScriptReference/MonoBehaviour.html]Monobehaviour[/url], which inherits from [url=https://docs.unity3d.com/Documentation/ScriptReference/Behaviour.html]Behaviour[/url], which inherits from [url=https://docs.unity3d.com/Documentation/ScriptReference/Component.html]Component[/url] (Hey, now we know that the scripts we're writing is actually A COMPONENT). If you look at the list of variables on Monobehaviour, you can see
[code]gameObject - The game object this component is attached to. A component is always attached to a game object.[/code]
There's also this:
[code]transform - The Transform attached to this GameObject. (null if there is none attached).[/code]
This information is enough to tell us that we can get the owner of the component (the script we're writing is also a component, remember?) by just calling gameObject (with lowercase G).
Save the script below as PrintOwnerAndReferenced.cs. Attach the script to any GameObject, and drag another GameObject (anything) to the public variable. Press play, and look at your console.
[code]using UnityEngine;
using System.Collections;
public class PrintOwnerAndReferenced : MonoBehaviour
{
public GameObject otherGameObject;
void Start()
{
// Prints "The owner of this script is <insert GameObject name>" in the console
Debug.Log("The owner of this script is "+gameObject);
// Prints "<insert GameObject name> is located at <insert position>" in the console
Debug.Log(""+gameObject+" is located at "+gameObject.transform.position);
// Same as above, but instead of calling gameObject and tell gameObject to call transform,
// we call the transform DIRECTLY
Debug.Log(""+gameObject+" is located at "+transform.position);
(if(otherGameObject)) // Check whether otherGameObject is null or not
{
// Prints "The referenced GameObject is <insert otherGameObject name>" in the console
Debug.Log("The referenced GameObject is "+otherGameObject);
// Prints "<insert otherGameObject name> is located at <insert otherGameObject position>" in the console
Debug.Log(""+otherGameObject+" is located at "+otherGameObject.transform.position);
}
}
}
[/code]
Lets say we want the player to shoot bullets by clicking left mouse button. We need a script for that, and we need a GameObject to attach the script.
By logic, the owner of the script should be the player. It doesn't make sense to let an Enemy to be the owner of the player's shooting script (Heck if I'm the enemy I'll destroy the script so the player can't attack anymore).
So lets say we make a [b]ShootBullet.cs[/b] and attach it to a GameObject called [b]First Person Controller[/b].
[b]Note that the example creates a new bullets[/b]
[code]using UnityEngine;
using System.Collections;
public class ShootBullet : MonoBehaviour
{
public GameObject bulletPrefab; // We need a reference(blueprint) of the objects we want to create, assign something here
void Update()
{
if(Input.GetButtonDown("Fire1")) // If we click left mouse button
{
// We can do this in 2 ways
Instantiate(bulletPrefab, gameObject.transform.position, gameObject.transform.rotation);
//Or this way: (comment out the top Instantiate and uncomment the bottom)
//Instantiate(bulletPrefab, transform.position, transform.rotation);
}
}
}[/code]
Above code will create a new GameObject every time the player clicks left mouse button, positioned to be AT the player's current position (at the same exact place the player is according to the scene). To make it spawn in front of the player instead of inside the player you need to do some stuff, but try to find the solution yourself.
I never understood the concept of quaternion, someone can tell me in simple words what is a quaternion and why i must set it on a instantiate method?
[QUOTE=gonzalolog;43395994]I never understood the concept of quaternion, someone can tell me in simple words what is a quaternion and why i must set it on a instantiate method?[/QUOTE]
It's the rotation of the object. When you instantiate you set the initial position and rotation.
Quaternion is a method of handling rotation/orientation of objects in 3D space. Unity's Transform.rotation is shown as Euler angles (XYZ) in the inspector, however internally it is Quaternion (XYZW). The reason for this is that Quaternion values are complex numbers (its plain gibberish for uneducated people, the XYZ in Quaternion are NOT angle).
The main reason Quaternion is used for rotation (instead of Euler angles) is that Quaternion do not suffer from [url=http://en.wikipedia.org/wiki/Gimbal_lock]Gimbal Lock[/url]. Search "Gimbal Lock explanation" on Youtube if you're visual/aural learner.
Unity's Quaternion has Quaternion.eulerAngles (returns rotation in Euler/Vector3) and Quaternion.Euler(x,y,z) (rotates to given values) built in if you need to use Euler angles.
[QUOTE=secundus;43396348]Quaternion is a method of handling rotation/orientation of objects in 3D space. Unity's Transform.rotation is shown as Euler angles (XYZ) in the inspector, however internally it is Quaternion (XYZW). The reason for this is that Quaternion values are complex numbers (its plain gibberish for uneducated people, the XYZ in Quaternion are NOT angle).
The main reason Quaternion is used for rotation (instead of Euler angles) is that Quaternion do not suffer from [url=http://en.wikipedia.org/wiki/Gimbal_lock]Gimbal Lock[/url]. Search "Gimbal Lock explanation" on Youtube if you're visual/aural learner.
Unity's Quaternion has Quaternion.eulerAngles (returns rotation in Euler/Vector3) and Quaternion.Euler(x,y,z) (rotates to given values) built in if you need to use Euler angles.[/QUOTE]
Thanks so much for your complete response!
[QUOTE=secundus;43395487]
[code]using UnityEngine;
using System.Collections;
public class ShootBullet : MonoBehaviour
{
public GameObject bulletPrefab; // We need a reference(blueprint) of the objects we want to create, assign something here
void Update()
{
if(Input.GetButtonDown("Fire1")) // If we click left mouse button
{
// We can do this in 2 ways
Instantiate(bulletPrefab, gameObject.transform.position, gameObject.transform.rotation);
//Or this way: (comment out the top Instantiate and uncomment the bottom)
//Instantiate(bulletPrefab, transform.position, transform.rotation);
}
}
}[/code]
Above code will create a new GameObject every time the player clicks left mouse button, positioned to be AT the player's current position (at the same exact place the player is according to the scene). To make it spawn in front of the player instead of inside the player you need to do some stuff, but try to find the solution yourself.[/QUOTE]
Thanks for the indepth response man. I understand what you mean now after trying that script.
For that code example where you make a GameObject called bulletPrefab, is that supposed to be a Prefab? I have a Prefab folder with a prefab_projectile that is in the form of a sphere.
I used this code :
public GameObject bulletPrefab = Resources.Load("prefab_projectile");
To try it but it didn't work. Should I change the GameObject to be a Prefab or?
Also, can you think of a simple example that I could do to make use of inheritance in Unity? Have to do it and not sure what I could do simply in Unity to demonstrate inheritance. Also since I have to implement a design pattern, in this case, Object Pool, I have to make stuff comparable and I'm not sure how when developing a game.
A Prefab is just a saved GameObject. In another words, a Prefab is a blueprint/template of a GameObject that you made.
[url=http://docs.unity3d.com/Documentation/ScriptReference/Resources.Load.html]Resources.Load[/url] returns an Object, not GameObject. Object is a base class for ALL things that can be referenced in Unity.
[img]https://dl.dropboxusercontent.com/u/7422512/Unity3D/2.PNG[/img]
It also means that GameObject inherits Object, as shown here:
[img]https://dl.dropboxusercontent.com/u/7422512/Unity3D/1.PNG[/img]
Your code doesn't work because of downcasting issue (you created an Object (superclass), and you assign it to GameObject(subclass of Object)). To fix this, cast it as the type that you want.
[code]public class NAMEOFCLASS : Monobehaviour {
public GameObject bulletPrefab
void Start()
{
// Not working, GameObject = Object
//bulletPrefab = Resources.Load("prefab_projectile");
// Working, GameObject = GameObject
bulletPrefab = Resources.Load("prefab_projectile") as GameObject;
//bulletPrefab = (GameObject)Resources.Load("prefab_projectile"); <- This method also works
// 2nd parameter is to tell what kind of Object we want in return.
// UNITY DOC: Only objects of type will be returned if this parameter is supplied.
//bulletPrefab = (GameObject)Resources.Load("prefab_projectile", typeof(GameObject)); <- works
//bulletPrefab = (GameObject)Resources.Load("prefab_projectile", typeof(GameObject)) as GameObject; <- works
}
}
[/code]
Thanks again for the indepth reply. However, that still isn't working for me for some strange reason. It makes sense that it should work, however I'm getting a compile error saying it can't convert UnityEngine.Object to UnityEngine.GameObject.
It says an explicit conversion exists(are you missing a cast?)
EDIT
Changing the code to say:
bulletPrefab = Resources.Load ("Prefabs/prefab_projectile") as GameObject;
ended up working. Is there a difference in the way you said and this way?
The only problem now is that the sphere doesn't appear. It appears for the frame I click it and disappears, it doesn't stay present in the scene.
Fixed up the code and the wrong stuff in previous post. Apparently you need to do an explicit cast, and the typeof(GameObject) parameter is actually telling what kind of object you want to get (this can be Material, or Texture2D for instance). My bad.
However for instantiate you don't have to do an explicit cast, since the first parameter of Instantiate is Object:
[code]
bulletPrefab = (GameObject)Resources.Load("new", typeof(GameObject));
Instantiate (Resources.Load ("new", typeof(GameObject)), transform.position, transform.rotation); //works, but avoid using this, as every time you call it the game loads a new one.
Instantiate (bulletPrefab, Vector3.zero, transform.rotation);
[/code]
Anyway Unity's documentation provides good explanation on these stuff, they even give examples in 3 scripting languages (most of it anyway) so you can just check/read them to learn stuff.
For inheritance, I'm not so sure. In AngryBots example, inheritance is used in Player/Enemy movement (superclass: MovementMotor.js; subclasses: FreeMovementMotor.js, HoverMovementMotor.js, MechMovementMotor.js, KamikazeMovementMotor.js).
MovementMotor inherits from Monobehaviour and only has 3 public Vector3 variables: movementDirection, movementTarget (unused), facingDirection. Nothing else is inside this script.
The subclasses of MovementMotor have the movement implementations, all of them different from each other. For example: FreeMovementMotor is absolute free movement (forward/backward, strafe left/right) and I believe MechMovementMotor moves like a vehicle (forward/backward, turn left/right).
PlayerMoveController.js is the script that handles player keyboard and mouse input. This script has a public MovementMotor variable, and on the player GameObject, FreeMovementMotor is the one referenced on this variable (yep, you can drag subclasses to it). I believe if you disable FreeMovementMotor, add MechMovementMotor,set it as reference to the MovementMotor and press play, the player will behave like a Mech.
This is confusing, in any case, fiddle with AngryBots, look at the Player GameObject and look at those 5 scripts I mentioned. Its in Javascript, but the difference is minimal.
Inheritance is also used for scripts that inherits from ScriptableObject, which do not need to be attached to any GameObject. Usually these ScriptableObjects are used for more advanced stuff, like creating an Item Database/System (superclass: Item; Subclass: Weapon, Armor, Consumable, QuestItem, Junk, Trophy).
Ah I see.
So if I am trying to make a Wizard game, would a good example of Inheritance be having a superclass such as Spell, which will have stuff such as damage and color etc, and then have subclasses such as FireSpell or IceSpell which have different damages and colors etc?
EDIT
Also, right now I have a simple weapon select. In the class WeaponSlot, I have a getSlotNumber method to return the currently selected weapon slot.
How can I return this from another script? I want to have it in my ObjectPool class.
So basically if I press 1, it shoots cubes, if I press 2 it shoots Spheres. So in the ObjectPool I will need to somehow use the getSlotNumber from WeaponSlots, but what is the best way of accessing the WeaponSlots class?
When I tried the following code:
WeaponSlots ws = new WeaponSlots();
int selectedWeapon = ws.getSlotNumber();
I get this warning
You are trying to create a MonoBehaviour using the 'new' keyword. This is not allowed. MonoBehaviours can only be added using AddComponent(). Alternatively, your script can inherit from ScriptableObject or no base class at all
UnityEngine.MonoBehaviour:.ctor()
WeaponSlots:.ctor()
ObjectPool:Start() (at Assets/Resources/Scripts/ObjectPool.cs:15)
If you want to prove that it can be done with inheritance, go ahead. The end result will be the proof that you understood the fundamentals of inheritance and polymorphism.
I don't really use inheritance in Unity though, so I can't really say whether it'll work good or not.
Ah okay thanks. Any ideas on the error with my weapon slots?
To get other scripts on runtime, use GetComponent<T>(). Unity disallows the usage on new keyword on MonoBehaviours and ScriptableObject. I think its the same reason why constructor is not allowed in Unity.
[code]
// Get component locally, usually used when processing raycast, collision etc
{
// OnTriggerEnter/Stay/Exit
// Physics.Raycast
// etc.
{
Health tempHealthScript = XXX.YYY.GetComponent<Health>();
// XXX can be (but not limited to):
// RaycastHit from using raycast
// Nothing at all, in this case its YYY.GetComponent<Health>();
//
// YYY can be (but not limited to):
// gameObject
// transform
// collider
// rigidbody
if(tempHealthScript) // Check if not null
tempHealthScript.DoStuff(); // Call public method from the script that we got
}
}
// Get and assign class members, usually private.
private WeaponSlot weapSlot;
private int selectedWeapon;
void Start()
{
weapSlot = GetComponent<WeaponSlot>(); // If getting component from SAME GameObject
weapSlot = transform.parent.GetComponent<WeaponSlot>(); // If getting component from the parent of this GameObject
weapSlot = transform.parent.parent.GetComponent<WeaponSlot>(); // If getting component from the parent's parent of this GameObject
weapSlot = transform.parent.GetComponent<WeaponSlot>(); // If getting component from the root of this GameObject
selectedWeapon = weapSlot.GetSlotNumber();
}
[/code]
Remember you can only access public members and methods.
Thats great man thanks for the help!
[QUOTE=secundus;43406530]
[code]
void Start()
{
weapSlot = GetComponent<WeaponSlot>(); // If getting component from SAME GameObject
weapSlot = transform.parent.GetComponent<WeaponSlot>(); // If getting component from the parent of this GameObject
weapSlot = transform.parent.parent.GetComponent<WeaponSlot>(); // If getting component from the parent's parent of this GameObject
weapSlot = transform.parent.GetComponent<WeaponSlot>(); // If getting component from the root of this GameObject
selectedWeapon = weapSlot.GetSlotNumber();
}
[/code]
~snip~[/QUOTE]
Where's "weapSlot = transform.GetComponentInChildren<WeaponSlot>();" ?
It's an expensive operation, but it still works.
I'm not sure if I'm using Daikon Forge incorrectly. I'm following the video tutorial for using TrueType Fonts as Dynamic Fonts.
The problem I get is at 0:56 seconds in the below video, I can't drag my new Dynamic Font into the Font field of the Label (dfLabel). Anyone been able to get this working?
[media]http://www.youtube.com/watch?v=Tx4NIIK5sWo[/media]
[b]Edit->[/b] Never mind, got it working by upgrading to latest version of unity and reimporting DF.
So does anyone have a clue on how to make cloth physics more accurate? I'm having a hard time because I'm making a soccer / pegball type of game, and my balls just go straight through the goal net :v:
[QUOTE=Oxu365;43423698]So does anyone have a clue on how to make cloth physics more accurate? I'm having a hard time because I'm making a soccer / pegball type of game, and my balls just go straight through the goal net :v:[/QUOTE]
Unless I'm mistaken, collisions at high speeds often end up going through eachother. Try changing the collision detection from discrete to continuous in the rigidbody settings of the ball (and possibly net, not sure).
[QUOTE=acds;43423764]Unless I'm mistaken, collisions at high speeds often end up going through eachother. Try changing the collision detection from discrete to continuous in the rigidbody settings.[/QUOTE]
Yeah I already tried that, no effect.
One possible way is to increase the physics update interval. IIRC physics updates are called during FixedUpdate.
[code]
Time.fixedDeltaTime = //value. Default is 0.02 (50 updates/sec)
// What it does is set the time (in millisecond) for FixedUpdate() calls.
[/code]
However this is not recommended. If this proves working, you might want to set the fixedDeltaTime only when your ball is inside the goal trigger, and reset when the next round starts.
Whipped up this:
[code]var football : Rigidbody; //Football prefab
var strictDelta : float = 0.008;
var fixedDelta : float = 0.02;
function OnTriggerEnter(football)
{
Time.fixedDeltaTime = strictDelta;
Debug.Log ("Time.fixedDeltaTime = 0.008");
}
function OnTriggerExit(football)
{
Time.fixedDeltaTime = fixedDelta;
Debug.Log ("Time.fixedDeltaTime = 0.02");
}[/code]
Seems to make it a little better, but still the occasional ball will go through.
[editline]5th January 2014[/editline]
Hmm, the problem actually seems to be in the cloth itself. The balls seem to slip through the gaps between vertices. If there was a way to increase the "resolution" of the cloth it could fix the problem.
Sorry, you need to Log In to post a reply to this thread.