I would like to override the didBeginContact function so as to implement custom logic when two physics objects in my scene collide.
I understand how this would be done in Swift by first setting the contact delegate to be the scene object itself and then setting up the didBeginContact function as below:
self.physicsWorld.contactDelegate = self
func didBeginContact(contact: SKPhysicsContact) {
//logic goes here
}
I am unable to work out how to implement such a system when using SpriteKit with Xamarin in C#. I have tried creating a custom Contact Delegate class which is a subclass of SKPhysicsContactDelegate and setting the scene's PhysicsWorld.ContactDelegate property to be an instance of this class but I noticed no change when running my application.
public class CollisionDelegate : SKPhysicsContactDelegate
{
public override void DidBeginContact(SKPhysicsContact contact)
{
if (contact.BodyA.CategoryBitMask == 1 &&
contact.BodyB.CategoryBitMask == 3)
{
contact.BodyB.Node.RemoveFromParent();
}
else if (contact.BodyA.CategoryBitMask == 3 &&
contact.BodyB.CategoryBitMask == 1)
{
contact.BodyA.Node.RemoveFromParent();
}
}
}
Then in my SKScene class:
public override void DidMoveToView(SKView view)
{
PhysicsWorld.ContactDelegate = new CollisionDelegate();
//Other scene initilaisation
}
Related
I am currently working on a game, and while designing a Main Menu for the game, I need to be able to access different GameObjects and enable/disable them for the user to access different parts of the menu. The different parts are held under their respective parent GameObjects, for example, all the GameObjects related to the "Options Menu" will be under a single empty GameObject called "Options".
Here is the code pertaining to a script that holds the references to all the different parent objects and the methods to enable them:
public class MenuSwitch : MonoBehaviour
{
public GameObject Main;
public GameObject Options;
public GameObject About;
public GameObject Load;
public void MainMenu()
{
Main.SetActive(true);
Options.SetActive(false);
About.SetActive(false);
Load.SetActive(false);
}
public void OptionsMenu()
{
Main.SetActive(false);
Options.SetActive(true);
About.SetActive(false);
Load.SetActive(false);
}
However. the problem is the navigation of the Menu has to be done by the player by typing 'commands'. For example, they would type '/options' to go to the options menu. This functionality will remain throughout the game, so I made another script to handle player commands from the in-game console. Now how do I call the methods from MenuSwitch, because making a MenuSwitch object inside my console script does not seem to work, it gives an error: "Object reference not set to an instance of an object".
Here is the script handling the commands specified in the main menu:
// Commands
string[] MainMenuCommands = { "./start", "./load", "./about", "./options", "./end" };
private void Update()
{
if (Input.GetKeyDown(KeyCode.Return))
{
// Reset the console
playerInput = console.text;
console.text = "";
// Main Menu Input
if (CheckCommand(playerInput) == true)
{
RunCommand(playerInput, scene);
}
}
}
void RunCommand(string _command, int _scene)
{
// Main Menu commands
if (_scene == 0)
{
if (_command == MainMenuCommands[0]) { StartCoroutine(MM_Start()); }
else if (_command == MainMenuCommands[1]) { MM_Load(); }
else if (_command == MainMenuCommands[2]) { MM_About(); }
else if (_command == MainMenuCommands[3]) { MM_Options(); }
else if (_command == MainMenuCommands[4]) { MM_End(); }
}
}
The MM methods are empty currently, that is where the enabling/disabling will take place. How do I enable or disable the GameObjects inside the MenuSwitch script? The objects are referenced in that script via the Unity inspector.
You could create an empty object and call it MenuManager, attach the MenuScript to it. Then in a script you want to call MenuSwitch functions from declare a class member like so:
public MenuSwitch menuManager;
Drag and drop the MenuManager empty gameObject in the inspector and then you can easily use all the public functions from MenuSwitch script by just calling them from the menuManager variable like so:
menuManager.MainMenu();
menuManager.OptionsMenu();
I hope it was helpful :)
I have a button that I made that is able to activate other objects. It is a physical button that, in this case, is activated by touching it with the player GameObject. It uses this script to activate the other objects:
public GameObject[] ThingsToActivate = { };
void Update()
{
if (activated)
{
foreach (var Object in ThingsToActivate)
{
Object.GetComponent<foo>().Active = true;
}
}
}
This works pretty good, but that means that everything that you put into the ThingsToActivate array has to have a script named foo. I'd like to put this button on the asset store, but I want it to be very easy to use. I'd like to make it so that you can name the script anything you want, as long as it has the public bool Active variable.
Is there any simple way to do this, like searching all of the scripts specifically for that variable, or maybe some sort of workaround?
To get all components regardless of type, use GetComponents<Component>().
To check if the component has a property called "Active", use GetType().GetProperty("Active"). If it returns a PropertyInfo instance, you can use its SetValue method to set it.
if (activated)
{
foreach (GameObject object in ThingsToActivate)
{
foreach (Component component in object.GetComponents<Component>())
{
var prop = component.GetType().GetProperty("Active");
if (prop != null) prop.SetValue(component, true);
}
}
}
You could use Reflection:
foreach (var Object in ThingsToActivate)
{
var prop = Object.GetComponent<foo>().GetType().GetPropery("Active");
if(prop != null && prop.PropertyType == typeof(bool)
prop.SetValue(Object.GetComponent<foo>(), true);
}
What kind of button is this? Why is it not possible that everyone who wants to use it inherits from a certain Type?
I would explicitly NOT use Reflection here!
I as a user/developer really wouldn't like to use your button asset and then wonder why it also changes a field in some of my own custom components that eventually has a field/property called Active ;)
I would rather recommend to use a dedicated parent class you have to inherit like e.g.
public abstract class YourButtonListener : MonoBehaviour
{
// I would even use a property here
// you'll see below why
public virtual bool Active { get; set;}
}
And use this as type and thereby yes, explicitly force your users/developers to explicitly use this as a type
public YourButtonListener[] ThingsToActivate;
and
foreach(var listener in ThingsToActivate)
{
listener.Active = true;
}
Then I as developer know I just have to inherit this type like
public class MyListener : YourButtonListener
{
// Now since I used a virtual property above
// I can either keep it ad a simple
// standard setter and getter
// or I can implement an own additional functionality like e.g.
private bool _active;
public override bool Active
{
get => _active;
set
{
_active = value;
// Here I can put whatever I like to happen when this is set
Debug.Log("I just got " + (value ? "activated" : "deactivated"));
}
}
}
Further notes in general:
Don't use GetComponent in Update store the references and reuse them.
By simply making your field of the correct type you don't need GetComponent at all in most of the cases. Additionally this forces any referenced GameObject to actually have such a component attached and hinders the developer to (by accident?) reference something else in the Inspector.
Do not use Update for poll checking bool values. Rather restructure your code in order to work more event driven e.g. by using a method instead like
public void SetActive(bool active)
{
foreach(var listener in ThingsToActivate)
{
listener.Active = active;
}
}
Typed on smartphone but I hope the idea gets clear
I need to have control of this method so that I can make a change in my app. But I couldn't make this implementation work, can anyone help?
Here is the Custom Renderer of my TabbedPage:
public class MainTabbedPageRenderer : TabbedRenderer, IUITabBarControllerDelegate
{
[Export("tabBarController:shouldSelectViewController:")]
public bool ShouldSelectViewController(UITabBarController tabBarController, UIViewController viewController)
{
return false;
}
}
The breakpoint does not stop there at all.
I have the impression that it does not stop at breakpoint because TabBarController is always null, but the screen loads and performs navigations normally, I also could not make this TabBarController be filled.
You can click on tabbar items using this method:
[Export("tabBar:didSelectItem:")]
public void ItemSelected(UITabBar tabbar, UITabBarItem item)
{
}
I don't see where you are assigning your delegate. That is likely why it is not hit, you have not assigned the delegate to the UITabBarController (which is the base class for TabbedRenderer). Also TabbedRenderer already assigns a delegate, so you likely do not want to replace it.
That said, Xamarin.iOS actually defines a C# delegate, called UITabBarSelection, for the ShouldSelectViewController protocol method. And there is a property on TabbedRenderer called ShouldSelectViewController that allows you to set this delegate method, so you should be able to just do this:
public class MainTabbedPageRenderer : TabbedRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
this.ShouldSelectViewController = ShouldSelectViewControllerHandler;
}
bool ShouldSelectViewControllerHandler(UITabBarController tabBarController, UIViewController viewController)
{
return false;
}
}
He everybody,
I'm trying to setup a project management class.
In order to see if somthing in the data changed i want to implement events on the lower level of the programming structure. I have some Classes extending the ProjectComponent Class. The base class has an event and event throwing methode, which the childcomponents can use.
Now I have a couple of custom list (nameley eList) in the project object.
Because all the child component have a common parent, ProjectComponent, i would like my custom list object (eList) to subscribe to the event when an object is added and unsubscribe when removed.
However when trying to prog this, i received the following error:
'ProjectComponent' does not contain a
definition for 'itemChanged' and no
extension method 'itemChanged'
accepting a first argument of type
'ProjectComponent'
Which is kind of wierd seeing as the class clearly has that public field.
Here is a the code:
public class ProjectComponent
{
public event ItemChanged itemChanged;
public void throwItemChangedEvent(ItemChangedEventArgs Arguments)
{
if (itemChanged != null)
itemChanged(new Object(), Arguments);
}
}
public class eList<ProjectComponent> : IList<ProjectComponent>
{
List<ProjectComponent> internalList = new List<ProjectComponent>();
public override void Add(ProjectComponent Item)
{
this.internalList.Add(Item);
Item.itemChanged += new ItemChanged(ItemChanged_Handler);
}
private void ItemChanged_Handler(object sender, ItemChangedEventArgs eventArgs)
{
//do stuff here
}
}
An example how it would be called is:
public eList<ChildClass> Children = new eList<ChildClass>();
The idea is that when an object in the list is edited the list object recieve an object like so:
Children.childstring = "anything";
At the moment the field inside the Children object is changed an event could be recieved.
My question is simply what am i doing wrong, why cant i suscribe to the ProjectComponent event inside the eList class?
Or does anyone know a better way to achive the same results?
Thanks in Advance,
Harry
Edit: Definition of ItemChanged delagate:
public delegate void ItemChanged(object sender, ItemChangedEventArgs eventArgs);
public class ItemChangedEventArgs : EventArgs
{
private String p_CallStack;
public String CallStack
{
get { return this.p_CallStack; }
set { this.p_CallStack = value; }
}
public ItemChangedEventArgs()
{
p_CallStack = "";
}
public ItemChangedEventArgs(String StackStart)
{
p_CallStack = StackStart;
}
}
you have 2 errors:
1.
in generic class definition you must use variables not existing classes:
public class eList<ProjectComponent>: ...
--> public class eList<T>: ...
in your case you want to do:
public class eList : IList<ProjectComponent>
2.
Item.itemChanged += new Item.itemChanged(ItemChanged_Handler);
new Item.itemChanged has no meaning, you have to use the underlying delegate type of your event:
Item.itemChanged += new ItemChanged(ItemChanged_Handler);
N.B:
your code does not respect at all design guidelines for c#
More informations here:Naming Guidelines
Shouldn't it be
Item.itemChanged += new ItemChanged(ItemChanged_Handler);
I have an interface (ICamera) which is implemented by 2 classes (FreeCamera, StaticCamera). The classes are inheriting from GameComponent.
Example definiton:
public class FreeCamera : GameComponent, ICamera
{
...
}
Now I'm adding the classes to the Game Components and register one of the components to a game service
private FreeCamera freeCam;
private StaticCamera staticCam;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
freeCam = new FreeCamera(this) { Enabled = true };
staticCam = new StaticCamera(this) { Enabled = false };
Services.AddService(typeof(ICamera, freeCam);
Components.Add(freeCam);
Components.Add(staticCam);
...
}
Then I want to change the provider for the service during the application flow with help of a toggle function
namespace Game1
{
protected override void Update(GameTime gameTime)
{
var keyboard = Keyboard.GetState();
if(keyboard.IsKeyDown(Keys.C))
{
if(freeCam.Enabled)
{
Services.RemoveService(typeof(ICamera));
Services.AddService(typeof(ICamera, staticCam);
freeCam.Enabled = !freeCam.Enabled;
staticCam.Enabled = !staticCam.Enabled;
}
else
{
Services.RemoveService(typeof(ICamera));
Services.AddService(typeof(ICamera, freeCam);
freeCam.Enabled = !freeCam.Enabled;
staticCam.Enabled = !staticCam.Enabled;
}
}
base.Update(gameTime);
}
}
The StaticCamera takes only input by mouse (you can rotate the camera), the FreeCamera can also moved by keyboard input. When I call the method above (by pressing C on the keyboard) the FreeCamera class gets deactivated but the viewport seems frozen and does not react to any input. When I call the method again after a short time the FreeCamera gets activated again and everything works as expected.
Now I have 2 questions regarding this:
Is it possible to change the service
provider of a game service in the
game loop?
Is there a better approach
to handle different camera types in a
game and switch between them easily?
Thanks in advance for any help.
Like you answered, use a camera manager. It acts as both a factory and a container for the current camera. The manager you can register as a service. Manager would look something like this:
public class CameraManager
{
private Dictionary<Type, ICamera> _cameras;
private ICamera _current;
public ICamera Current
{
get
{
return _current;
}
}
// Sets the current cammera to the internal instance of the camera type
public void SetCurrent<T>() where T : ICamera
{
if (!_cameras.ContainsKey(typeof(T)))
{
// TODO: Instantiate a new camera class here...
}
_current = _cameras[typeof(T)];
}
}
This is just rough code - would need to be filled in more. One limitation is you can only have one camera per type. Giving cameras a string name, or an enum flag would let you toggle between an arbitrary number of cameras.
Thanks for the tip. I just wrote the code down from my head without my IDE at hand, so please do not look too much into syntax errors etc.
In my game I'm using wrapper classes for the input. The code is just a brief example of the problem - how to substitute a game service if both classes are using the same interface.
My new idea: I could use a "manager" class (like CameraManager in this case) which has the following methods
public void SetCameraType(CameraType type) //CameraType could be an enum
public ICamera GetCamera()
and then put the manager class into the service (with its own interface like ICameraManager).
Edit: this was considered as an answer to the comment above ... but it seems I clicked the wrong button - sorry
I think if you left off the code about adding and removing the service in the Update you'd be good and added lines changing the Visible property. The Enable property effects calls to Update, but the Visible property effects calls to Draw.
So I'd suggest the Update look like this:
protected override void Update(GameTime gameTime)
{
var keyboard = Keyboard.GetState();
if(keyboard.IsKeyDown(Keys.C))
{
if(freeCam.Enabled)
{
freeCam.Enabled = false;
freeCam.Visible = false;
staticCam.Enabled = true;
staticCam.Visible= true;
}
else
{
freeCam.Enabled = true;
freeCam.Visible = true;
staticCam.Enabled = false;
staticCam.Visible= false;
}
}
base.Update(gameTime);
}