diff --git a/Assets/Prefabs/GridViewItem.prefab b/Assets/Prefabs/GridViewItem.prefab index 14e91a1..f2699cc 100644 --- a/Assets/Prefabs/GridViewItem.prefab +++ b/Assets/Prefabs/GridViewItem.prefab @@ -13,6 +13,7 @@ GameObject: - component: {fileID: 948105846380880608} - component: {fileID: 1804675914970317424} - component: {fileID: 302494393966301419} + - component: {fileID: 939561850148325245} m_Layer: 5 m_Name: InfoPanel m_TagString: Untagged @@ -124,6 +125,18 @@ Canvas: m_SortingLayerID: -960857747 m_SortingOrder: 0 m_TargetDisplay: 0 +--- !u!114 &939561850148325245 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 845423096962593660} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 94c9e658942984942b8d3590e141bc10, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &1245163151616179787 GameObject: m_ObjectHideFlags: 0 @@ -535,7 +548,7 @@ GameObject: - component: {fileID: 1985633672282538122} - component: {fileID: 7182777043849646237} - component: {fileID: 7595911457622289179} - - component: {fileID: 5650403253300554073} + - component: {fileID: 5183905483240302633} m_Layer: 5 m_Name: GridViewItem m_TagString: Untagged @@ -602,7 +615,7 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 ---- !u!114 &5650403253300554073 +--- !u!114 &5183905483240302633 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -611,14 +624,14 @@ MonoBehaviour: m_GameObject: {fileID: 1985633672282538121} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 04d5ea5fa6876284fb8c44e4316a34ca, type: 3} + m_Script: {fileID: 11500000, guid: 5420b7790c2c8c544b08a3f8adc9f27f, type: 3} m_Name: m_EditorClassIdentifier: highLight: {fileID: 4763744946543245952} - infoPanel: {fileID: 845423096962593660} icon: {fileID: 1985633671483540185} iconAtlas: {fileID: 4343727234628468602, guid: 61885a51c5dad46cd8f257139ddcc43a, type: 2} + infoPanel: {fileID: 939561850148325245} --- !u!1 &2358759312657327302 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Prefabs/ListViewItemSingle.prefab b/Assets/Prefabs/ListViewItemSingle.prefab index 29739d7..2a33e91 100644 --- a/Assets/Prefabs/ListViewItemSingle.prefab +++ b/Assets/Prefabs/ListViewItemSingle.prefab @@ -969,7 +969,8 @@ GameObject: - component: {fileID: 6553243021197451812} - component: {fileID: 6553243021197451811} - component: {fileID: 6553243021197451810} - - component: {fileID: 6768523180603805952} + - component: {fileID: 1645053654222213013} + - component: {fileID: 1445738884463823766} m_Layer: 5 m_Name: ListViewItemSingle m_TagString: Untagged @@ -1061,7 +1062,7 @@ MonoBehaviour: m_ChildControlHeight: 0 m_ChildScaleWidth: 0 m_ChildScaleHeight: 0 ---- !u!114 &6768523180603805952 +--- !u!114 &1645053654222213013 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1070,14 +1071,25 @@ MonoBehaviour: m_GameObject: {fileID: 6553243021197451808} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 04d5ea5fa6876284fb8c44e4316a34ca, type: 3} + m_Script: {fileID: 11500000, guid: 9232911ef3a75234f99d753eba3f5ea0, type: 3} m_Name: m_EditorClassIdentifier: highLight: {fileID: 5361503465745185307} - infoPanel: {fileID: 3305316203439612742} icon: {fileID: 4407477508750570901} iconAtlas: {fileID: 4343727234628468602, guid: 61885a51c5dad46cd8f257139ddcc43a, type: 2} +--- !u!114 &1445738884463823766 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6553243021197451808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 94c9e658942984942b8d3590e141bc10, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &6553243021295918077 GameObject: m_ObjectHideFlags: 0 @@ -1089,6 +1101,7 @@ GameObject: - component: {fileID: 6553243021295918078} - component: {fileID: 6553243021295918016} - component: {fileID: 6553243021295918079} + - component: {fileID: 2502180100573894507} m_Layer: 5 m_Name: Name m_TagString: Untagged @@ -1234,6 +1247,18 @@ MonoBehaviour: - {fileID: 0} m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!114 &2502180100573894507 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6553243021295918077} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f1bf98089f9db1b4aacb219d05609744, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &6553243022573261482 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scenes/NewShop.unity b/Assets/Scenes/NewShop.unity index bba3ac9..629d92a 100644 --- a/Assets/Scenes/NewShop.unity +++ b/Assets/Scenes/NewShop.unity @@ -134,6 +134,7 @@ GameObject: - component: {fileID: 78292606} - component: {fileID: 78292605} - component: {fileID: 78292604} + - component: {fileID: 78292608} m_Layer: 5 m_Name: InfoPanel m_TagString: Untagged @@ -245,6 +246,18 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 78292602} m_CullTransparentMesh: 0 +--- !u!114 &78292608 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 78292602} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 94c9e658942984942b8d3590e141bc10, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &87758255 GameObject: m_ObjectHideFlags: 0 @@ -2960,6 +2973,7 @@ MonoBehaviour: instructionText: {fileID: 1416129356} layoutGroup: {fileID: 1865708447} ownModel: {fileID: 132445007} + infoPanel: {fileID: 78292608} --- !u!1 &849412832 GameObject: m_ObjectHideFlags: 0 @@ -5070,6 +5084,7 @@ GameObject: - component: {fileID: 1287258905} - component: {fileID: 1287258907} - component: {fileID: 1287258906} + - component: {fileID: 1287258908} m_Layer: 5 m_Name: Name m_TagString: Untagged @@ -5215,6 +5230,18 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1287258904} m_CullTransparentMesh: 0 +--- !u!114 &1287258908 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1287258904} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f1bf98089f9db1b4aacb219d05609744, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &1320263017 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/Shop/Tests/ShopUnitTests.cs b/Assets/Scripts/Shop/Tests/ShopUnitTests.cs index db6f710..65432a9 100644 --- a/Assets/Scripts/Shop/Tests/ShopUnitTests.cs +++ b/Assets/Scripts/Shop/Tests/ShopUnitTests.cs @@ -94,7 +94,7 @@ namespace Tests //was thrown Assert.Throws(delegate { - shopView.OnSelected(item); + //shopView.OnSelected(item); // TODO: check items for selection in here },"Error selecting specified item"); Assert.IsFalse(true,"Previous item is still selected!"); } diff --git a/Assets/Scripts/Shop/View/ShopView.cs b/Assets/Scripts/Shop/View/ShopView.cs index 782af3a..214c77f 100644 --- a/Assets/Scripts/Shop/View/ShopView.cs +++ b/Assets/Scripts/Shop/View/ShopView.cs @@ -12,7 +12,7 @@ using TMPro; /// informationoutside of the BuyModel, for example, the money amount from the player's inventory, then you need to either keep a /// reference to all the related models, or make this class an observer/event subscriber of the related models. /// -public abstract class ShopView : MonoBehaviour, IShopModelObserver +public abstract class ShopView : MonoBehaviour { public ShopModel ShopModel => model; //A getter to access shopModel. Will access inventory of trade partner in sell mode! @@ -158,19 +158,20 @@ public abstract class ShopView : MonoBehaviour, IShopModelObserver buyButton.gameObject.SetActive(true);//Show the buy button for the mouse controler } - public void OnSelected(Item item) - { - Debug.Log("View selects item: " + item.name,this); - RepopulateItemIconView(); - } - - public void OnRemoved(Item item) - { - RemoveItemFromView(item); - } - - public void OnAdded(Item item) - { - throw new NotImplementedException(); - } + // These three are from the observable interface, and it was decided to leave this stuff to the implementation for now. Keeping here for reference + // public virtual void OnSelected(Item item) + // { + // Debug.Log("View selects item: " + item.name,this); + // RepopulateItemIconView(); + // } + // + // public virtual void OnRemoved(Item item) + // { + // RemoveItemFromView(item); + // } + // + // public virtual void OnAdded(Item item) + // { + // throw new NotImplementedException(); + // } } diff --git a/Assets/Scripts/Shop/View/ShopViewList.cs b/Assets/Scripts/Shop/View/ShopViewList.cs index 5387f80..7cb226f 100644 --- a/Assets/Scripts/Shop/View/ShopViewList.cs +++ b/Assets/Scripts/Shop/View/ShopViewList.cs @@ -10,9 +10,11 @@ using UnityEngine.UI; /// This view is meant to be used in conjunction with a list. Realistically, it is mostly similar to the grid view, /// as both operate with prototypes! /// -public class ShopViewList : ShopView +public class ShopViewList : ShopView, IShopModelObserver { private VerticalLayoutGroup _listLayoutGroup; // This is essentially just a reference to ShopView's layout group but with the correct type + + [SerializeField] private ViewItemInfoPanel infoPanel; //protected ViewConfig viewConfig; //To set up the grid view, we need to know how many columns the grid view has, in the current setup, //this information can be found in a ViewConfig scriptable object, which serves as a configuration file for @@ -24,7 +26,9 @@ public class ShopViewList : ShopView //iewConfig = Resources.Load("ViewConfig");//Load the ViewConfig scriptable object from the Resources folder //Debug.Assert(viewConfig != null); Debug.Assert(_listLayoutGroup != null); + Debug.Assert(infoPanel != null); base.Awake(); + model.RegisterObserver(this); print("ShopView Grid Initialised"); } @@ -79,4 +83,21 @@ public class ShopViewList : ShopView if(!correctLayout) Debug.LogError("Layout group is not of type Vertical!",this); //else Debug.Log("Grid shop view validated",this); } + + + public void OnSelected(Item item) + { + if(item != null) infoPanel.gameObject.SetActive(true); + infoPanel?.SetItemInfo(item); // ? works here as it's meant to live through the whole lifetime of this gameobject anyway + } + + public void OnRemoved(Item item) + { + infoPanel?.SetItemInfo(null); // This should set the item info to nothing, effectively disabling it + } + + public void OnAdded(Item item) + { + throw new NotImplementedException(); + } } diff --git a/Assets/Scripts/Shop/View/ViewItemContainer.cs b/Assets/Scripts/Shop/View/ViewItemContainer.cs index 4397f7d..dd9cbc1 100644 --- a/Assets/Scripts/Shop/View/ViewItemContainer.cs +++ b/Assets/Scripts/Shop/View/ViewItemContainer.cs @@ -14,36 +14,32 @@ using UnityEngine.U2D; /// and display the details of the item. The original implementation was hardcoded for the grid view. We use patterns to /// make this one a little more universally useful /// -public class ViewItemContainer : MonoBehaviour, IItemContainer, IShopModelObserver +public abstract class ViewItemContainer : MonoBehaviour, IItemContainer, IShopModelObserver { public Item Item => item;//Public getter for the item, required by IItemContainer interface. // IItemContainer interface requires to know whether an item is selected visually or not. This implementation determines that by checking the info panel - public bool IsSelected { - get { return infoPanel.gameObject.activeSelf; } - set { infoPanel.SetActive(value); highLight.SetActive(value);} + public virtual bool IsSelected { + get { return highLight.gameObject.activeSelf; } + set { highLight.SetActive(value);} } //Link to the highlight image (set in prefab) [SerializeField] - private GameObject highLight; + protected GameObject highLight; - //Link to the infomation panel (set in prefab), prototype pattern [SerializeField] - private GameObject infoPanel; - - [SerializeField] - private Image icon; + protected Image icon; //Link to the atlas of all the item icons, use to retrieve sprites for items. For more information of the API check: // https://docs.unity3d.com/2019.3/Documentation/Manual/class-SpriteAtlas.html [SerializeField] - private SpriteAtlas iconAtlas; + protected SpriteAtlas iconAtlas; //link to the original item (set in Initialize) - private Item item; + protected Item item; - private IDisposable _unsubscriber; // If this item manages its own lifetime, this will not be null + private IDisposable unsubscriber; // If this item manages its own lifetime, this will not be null //------------------------------------------------------------------------------------------------------------------------ // Initialize() //------------------------------------------------------------------------------------------------------------------------ @@ -51,28 +47,21 @@ public class ViewItemContainer : MonoBehaviour, IItemContainer, IShopModelObserv //Stores the item this.item = item; - _unsubscriber = unsubscriber; - //Sets the highlight image and infoPanel's visibility - //if (isSelected) { - // highLight.SetActive(true); - // infoPanel.SetActive(true); - //} + this.unsubscriber = unsubscriber; // Clones the first Sprite in the icon atlas that matches the iconName and uses it as the sprite of the icon image. Sprite sprite = iconAtlas.GetSprite(item.iconName); - - // Sets name in all locations the prototype has a name component attached to - var nameComps = GetComponentsInChildren(true); // Include inactives! - foreach (var name in nameComps) - { - name.SetName(item.iconName); // Use iconname for now, debugging - } if (sprite != null) { icon.sprite = sprite; } + + IsSelected = false; + OnInitialize(item); } + protected abstract void OnInitialize(Item item); + // When the observable fires, check if we're the view corresponding to the selected item. Select if we are! public void OnSelected(Item item) { @@ -94,6 +83,6 @@ public class ViewItemContainer : MonoBehaviour, IItemContainer, IShopModelObserv // The reason we do this in OnDestroy() is so we don't have a memory leak when this gets removed externally somehow private void OnDestroy() { - _unsubscriber?.Dispose(); // Careful! If we don't make this thing aware that it manages itself, and we forget to manage it, we have a memory leak + unsubscriber?.Dispose(); // Careful! If we don't make this thing aware that it manages itself, and we forget to manage it, we have a memory leak } } diff --git a/Assets/Scripts/Shop/View/ViewItemContainerGrid.cs b/Assets/Scripts/Shop/View/ViewItemContainerGrid.cs new file mode 100644 index 0000000..4a5d4cb --- /dev/null +++ b/Assets/Scripts/Shop/View/ViewItemContainerGrid.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using TMPro; +using Unity.Collections.LowLevel.Unsafe; +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.U2D; + +/// +/// Grid version of view container, which does feature an info panel! +/// +public class ViewItemContainerGrid : ViewItemContainer +{ + public override bool IsSelected { + get => highLight.gameObject.activeSelf; + set { infoPanel.gameObject.SetActive(value); highLight.SetActive(value);} + } + + //Link to the infomation panel (set in prefab), prototype pattern + [SerializeField] + private ViewItemInfoPanel infoPanel; + + protected override void OnInitialize(Item item) + { + infoPanel.SetItemInfo(item); // Grid info comes with a panel, so we set its info just once + } +} diff --git a/Assets/Scripts/Shop/View/ViewItemContainerGrid.cs.meta b/Assets/Scripts/Shop/View/ViewItemContainerGrid.cs.meta new file mode 100644 index 0000000..f73442b --- /dev/null +++ b/Assets/Scripts/Shop/View/ViewItemContainerGrid.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5420b7790c2c8c544b08a3f8adc9f27f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Shop/View/ViewItemContainerList.cs b/Assets/Scripts/Shop/View/ViewItemContainerList.cs new file mode 100644 index 0000000..d9f2150 --- /dev/null +++ b/Assets/Scripts/Shop/View/ViewItemContainerList.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using TMPro; +using Unity.Collections.LowLevel.Unsafe; +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.U2D; + +/// +/// List version of the view item container. Does not feature an info panel +/// +public class ViewItemContainerList : ViewItemContainer +{ + public override bool IsSelected { + get => highLight.gameObject.activeSelf; + set => highLight.SetActive(value); + } + + private ViewItemInfoPanel itemInfo; + + protected override void OnInitialize(Item item) + { + // We just use the automatic component based item info panel stuff per-item here! + itemInfo = GetComponent(); + itemInfo?.SetItemInfo(item); + } +} diff --git a/Assets/Scripts/Shop/View/ViewItemContainerList.cs.meta b/Assets/Scripts/Shop/View/ViewItemContainerList.cs.meta new file mode 100644 index 0000000..40e3970 --- /dev/null +++ b/Assets/Scripts/Shop/View/ViewItemContainerList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9232911ef3a75234f99d753eba3f5ea0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Shop/View/ViewItemInfoPanel.cs b/Assets/Scripts/Shop/View/ViewItemInfoPanel.cs new file mode 100644 index 0000000..c850cad --- /dev/null +++ b/Assets/Scripts/Shop/View/ViewItemInfoPanel.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +/// +/// This component searches all children for a bunch of other components such as names, descriptions, stats, etc +/// and updates them with all necessary information whenever it is updated. +/// It is assumed that children of a view info panel never get destroyed separately, as it is treated as one object. +/// Similarly, it is assumed that all children already exist at the time of startup. +/// +public class ViewItemInfoPanel : MonoBehaviour +{ + private List names;// = new List(); + private void Awake() + { + UpdateComponentInfo(); + } + + private void UpdateComponentInfo() + { + names = GetComponentsInChildren().ToList(); + Debug.Assert(names != null,this); + //if (names == null) names = ; + // TODO: Create and add all other types in here as components! + } + + // When this is set, it updates all relevant game objects to reflect the item's propertiese. + public void SetItemInfo(Item item) + { + if (item == null) + { + gameObject.SetActive(false); // If the seelcted item doesn't exist, disable the whole panel + return; + } + if(names == null) UpdateComponentInfo(); // Assume that if the names component is null, we probably never initialised + //gameObject.SetActive(true); + foreach (var name in names) + { + name.SetName(item.name); + } + } +} diff --git a/Assets/Scripts/Shop/View/ViewItemInfoPanel.cs.meta b/Assets/Scripts/Shop/View/ViewItemInfoPanel.cs.meta new file mode 100644 index 0000000..e6caa8e --- /dev/null +++ b/Assets/Scripts/Shop/View/ViewItemInfoPanel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 94c9e658942984942b8d3590e141bc10 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: