Mouse clicks C# XNA - c#

This has been bothering me for quite some time so here we go...
I'm making a 2D game using XNA framework and part of the game needs the usage of mouse click funtions in UI. By using these textures as buttons it makes another window to pop up with more functions. Now the problem is when you create a button and use it, it will open another window with more buttons in it. Because these 2 buttons on different windows are at the same location, that one mouse click operates both buttons and makes the action of the last button instantly rather than having to click twice.
The real question is how do I use sprites as buttons rather than checking the position and checking if that possition is clicked?
Thanks in advance for any comments.

I created a basic UI framework that has Windows with Controls on them. Windows are stacked by zOrder as are the controls on each window. There is a ScreenManager class that updates every tick that tracks the mouse. When it sees a button click it walks the window stack from top to bottom looking for the first window that contains the click coordinates. It then calls the OnClick sub of that window instance, which does the same thing for the controls on the window. Each method stops walking the control stack as soon as it finds the first control that contains the click coords.
Each unique window in my game is a subclass of that basic window class that creates child control instances and lays them out in the specific way for it's layout. Controls like buttons raise a clicked event that the window subclass handles to do the logic needed for that button.

You could use a state manager in which the proper UI live.
In your case, the first state would have your first buttons, lets call it FirstGameState. When you click on them, the state machine gets you to a another state, lets call it MenuState. You can implement your state manager in a way that allows you to decide who handle events and who doesn't. The only state that handles your click events would be the one flagged to do so. The rest would only draw and update the visual content but handle no user events.
Here is an example for you:
namespace States
{
class StateManager
{
List<GameState> _states = new List<GameState>();
List<GameState> _statesCopy = new List<GameState>();
public Game Game { get; private set; }
public SpriteBatch SpriteBatch { get; private set; }
public StateManager(Game game, SpriteBatch sb)
{
Game = game;
SpriteBatch = sb;
}
public void AddState(GameState state)
{
_states.Add(state);
}
public void RemoveState(GameState state)
{
_states.Remove(state);
}
public void Update(GameTime gameTime)
{
_statesCopy.Clear();
foreach (GameState state in _states)
if (state.RequireUpdate)
_statesCopy.Add(state);
foreach (GameState state in _statesCopy)
if (state.RequireUpdate)
state.Update(gameTime);
}
public void Draw()
{
foreach (GameState state in _states)
state.Draw();
}
}
}

Related

Swiping images in C# Windows Forms app (Tinder swipe)

I really need to add the possibility of swiping images like in dating apps (Tinder maybe) in my own app. If the image is swiped to the left, then a certain value should be assigned to the variable (for example, +1). If to the right, then nothing should change (+0 to the variable). After swiping the image, the next image should float smoothly (from the front, from the bottom, it doesn't matter).
I tried to do it myself, but there are no ideas how this can be done. I understand that it will be more difficult to do this on Windows Forms than on WPF. I have only recently started to be interested in WPF, so solving this problem on WPF would also be useful, but Windows Forms is still a priority. Please help me solve this issue.
You forgot to define "swipe". Winforms doesn't have the notion of finger input, only the notion of mouse drag.
Do you want, that if the operator drags the mouse to the left that the image moves with it? Is a small drag enough, or should the operator drag the image completely outside the window?
What should happen if the operator drags a small part, but stops dragging? Should the image move back as if there was no drag? Or should the image stay dragged halfway?
Model
You used the word Image, but in fact the images stands for something more: in Tinder it stands for the person behind the image, a name, a birthdate, a description, and other parts, among which an image.
Let's call this a Profile: every profile has several properties, among others an Image.
class Profile
{
public Image Image {get; set;}
...
}
In your model you will need a FIFO sequence of "Profiles to be shown", a collection of rejected Profiles and a collection of accepted Profiles. You didn't say what you wanted to do with the rejected and accepted Profiles, so all I do is put the Rejected Profiles in a Repository, and the accepted ones in a different Repository.
What happens in the repository is hidden for the model. It might be that you delete everything, or you save it in a file, or a database, or whatever, your Model doesn't have to know. All it has to know is that both repositories need to have an interface to put the Profiles in:
interface IProfileRepository
{
void Add (Profile profile);
}
The repository with the rejected images will probably just throw the Profile away, while the other repository might do things like notify the owner of the Profile that he has been accepted.
We also need some input Profiles. I also don't know where they come from:
interface IProfileSource
{
Profile GetProfile(); // returns the next Profile
}
The actual ProfileSource might read the data from an XML file, or from the internet, or whatever, this is outside the question.
So in you program you will have the following:
class ProfileModel
{
private IProfileSource ProfileSource {get;} = new ...;
private IProfileRepository AcceptedProfiles {get;} = new ...;
private IProfileRepository RejectedProfiles {get;} = new ...;
public Profile GetNextProfile()
{
return ProfileSource.GetProfile();
}
public void AcceptProfile(Profile profile)
{
AcceptedProfiles.Add(profile);
}
public void RejectProfile(Profile profile)
{
RejectedProfiles.Add(profile);
}
View
The form that will display the images of the Profile will need a UserControl that will show a Profile. It is hidden what is shown of the Profile. You will probably only show the Image, but if you want, you can let it show the Age of the person, or the Name, Location, etc. All that your program knows is that you can ask the ProfileControl to show a Profile, what is shown, and how, is up to the ProfileControl.
Use visual studio to create a new UserControl, named ProfileControl. Use Visual Studio designer to draw on the control what you want to show when a Profile needs to be shown. If you only want to show the Image, add a PictureBox to the ProfileControl and let it dock. If you also want to show the Name, add a Label, etc
class ProfileControl : UserControl
{
private Profile profile;
public ProfileControl()
{
InitializeComponents();
}
public Profile Profile
{
get => this.profile;
set
{
if (this.Profile != value)
{
this.profile = value;
this.pictureBox1.Image = this.profile.Image;
}
}
}
}
Consider to add an event ProfileChanged and a protected method OnProfileChanged, to notify others that this ProfileControl shows a new Image.
You will need another UserControl that will do the dragging of the ProfileControl. It will have two ProfileControls: the current one and the next one. Upon MouseDrag the location of the current ProfileControl and the next ProfileControl will change. The next ProfileControl will be adjacent to the current one, depending on the direction of the drag.
This SwipeControl hides how the swiping is done. Users of the SwipeControl (= software, not operator), will only set the current and the next Profile, and it gets notified whenever the current profile is accepted or rejected via events. The event will automatically set the Next profile (if there is one)
Use the visual studio designer to give the SwipeControl two ProfileControls. Add events handlers for events:
MouseDown: remember current mouse position as DragStartPosition. Give CurrentProfileControl and NextProfileControl the size of the ClientArea of the SwipeControl. Set the Location of the CurrentProfileControl to (0, 0), so it is in the upper left corner of the ClientArea of the SwipeControl. NextProfileControl is still not visible, we don't know whether the operator will swipe to the left or to the right.
MouseMove: the horizontal distance that the mouse travelled = current mouse position X - DragStartPosition X. Shift the X location CurrentProfileControl with this Distance travelled. Decide whether NextProfileControl should be on the left or on the right side of CurrentProfileControl. Calculate the Location. Make NextProfileControl visible.
MouseUp: If Distance Travelled is more than some minimal, then set the swipe complete, otherwise undo: dock current and make next invisible.
SwipeComplete: if Accepted raise event ProfileAccepted, if Rejected raise event ProfileRejected. The Profile in the NextProfileControl is set to CurrentProfileControl. Fetch the NextProfile and put it in the NextProfileControl
class SwipeControl : CustomControl
{
public Profile CurrentProfile
{
get => this.CurrentProfileControl.Profile;
set => this.CurrentProfileControl.Profile = value;
}
public Profile NextProfile
{
get => this.NextProfileControl.Profile;
set => this.NextProfileControl.Profile = value;
}
public event EventHandler ProfileAccepted;
public event EventHandler ProfileRejected;
protected virtual void OnProfileAccepted()
{
// raise event ProfileAccepted
this.ProfileAccepted?.Invoke(this, EventArgs.Empty);
}
Use visual studio designer to add the event handlers and implement the code as written.
##The SwipeForm##
Use visual studio designer to add the SwipeControl to the SwipeForm. Also add the Model.
Subscribe to the Accepted / Rejected events of the SwipeControl.
Upon load of the form: get the first and the next Profile from the model and put them in the SwipeControl
Upon event ProfileAccepted: get the CurrentProfile from the SwipeControl and put it in the model as Accepted. The nextProfile will be the current one. Get the next from the model and set this as next profile in the SwipeControl.
Do something similar with event ProfileRejected

Back button on ui appears until you hit options and back

New to coding here, setting up a UI in unity and having a visual issue where the back button appears until I hit options and back on the start up page, any reccomendations for a fix?
Image showing back button behind the quit button
Settings of the image on the right
You can use Gameobject.setactive(true/false) and try to manage the panel by making empty game object inside UI Canvas and name it as a panel so the whole button became a child and you can easily manage it
for example like this one
public Gameobject startPanel;
public Gameobject optionPanel;
public void Startpnl()
{
//deadActive optionPanel and Activate startPanel
startPanel.setActive(true);
optionPanel.setActive(false);
}
public void optionpnl()
{
//deadActive starPanel and Activate OptionPanel
startPanel.setActive(false);
optionPanel.setActive(true);
}

Windows Mixed Reality - AttachToController

So I'm using the AttachToController script to attach a window floated on top of the controller - which works great. In the script that calls up the window, I figure out which hand pressed the controller's menu button and set the Handedness field appropriately (Left or Right). The problem I'm trying to solve is this: Let's say the user clicks on the right controller's menu button and then later on, the left menu button is clicked. The problem I'm experiencing is that even though I've altered the Handedness field, the window still appears attached to the right controller.
private void InteractionManager_InteractionSourcePressed(InteractionSourcePressedEventArgs args)
{
hand = args.state.source.handedness;
...
}
private void SetHandednessAndActivate(GameObject go)
{
AttachToController script = go.GetComponentInChildren<AttachToController>();
if (script != null)
{
script.Handedness = hand;
}
go.SetActive(true);
}
Just to be clear, if the user clicks the left controller menu button first, the window is always on the left and the same holds true for the right controller. What I want is for the window to move to whichever controller is used.
Instead of
script.Handedness = hand;
Use
script.ChangeHandedness(hand);
All the other bits are handled by the script.

Keep Links between two gameObjects when scenes change in unity

I'm Working on a game, and i want to create a mute button. So i wrote a script for that and i attach this script into a gameObject that don't destroy on load.
I link the script with a UI Button present in a main menu. This UI button is destroy when i'm changing scenes.
when i start my game, and i click on the button, the audio turns off, and when i click back, it turns on.
But when i change to another scene, and i go back to the main menu, my script doesn't have the UI Button attach to it. so when i touch the button the audio doesn't change is behavior
I would like to know if it's possible to maintain the link between the UI Button and the script (attach to a normal GameObject), even if the UI Button is destroyed?
i tried this:
ButtonGameObject = GameObject.Find("UI Button");
but it doesn't work.
How can i fix that?
Thanks a lot.
There are many ways to work around this, but here's one:
Step 1: If you haven't already done so, implement a weak singleton pattern on your mute script (let's call it MuteScript.cs for now).
private static MuteScript singleton {get; private set;}
private void Awake() {
if (singleton == null) singleton = this;
[whatever other stuff you were already doing in Awake()]
}
public static void ToggleMute(Graphic graphic)
{
singleton._ToggleMute(graphic);
}
private void _ToggleMute(Graphic graphic)
{
[whatever code you were running in your original mute method]
}
Step 2: Attach a simple script to your UI button:
public class MuteButton: MonoBehaviour
{
Graphic myGraphic;
private void Awake() {
myGraphic = GetComponent<Graphic>();
}
public void OnClick() {
MuteScript.ToggleMute(myGraphic);
//I assume you want to do something like change the colour of the button when
//the player toggles it. Passing the Graphic to the MuteScript is the easiest
//way of doing this. If you really want to keep your code clean, though,
//I recommend expanding the MuteButton class with methods to take care of
//the UI side of things.
}
}
Step 3: In Unity Editor, setup your button to call its own OnClick() method, not the MuteScript method.
-
Now when you click the button, it will call the static MuteScript.ToggleMute(), which accesses the static-cached singleton reference, which in turn points back to your original object.
Singletons and static accessors are great for efficiency in Unity because they save you from having to call expensive search functions like FindObjectsOfType(). The only gotcha is that you have to be careful about not having multiple copies of a singleton-class object lying around, especially when using DontDestroyOnLoad().
So a better approach rather than having a script search and grab the component is to use a PlayerPrefs class from Unity. Essentially, it will hold onto all important aspects of the game and auto fill information.
This is a great tool for a lot of user customization aspects of a game. When using this, have a script (sceneController would be a good name) that will run when the scene starts (create a blank object at 0,0,0) and then under void Start() have the script grab the mute/unmute button: GameObject.Find("MuteButton") or (my favorite) give it a tag called MuteButton and run: GameOject.FindWithTag("MuteButton"). Also once you get a link to the button, add a listener to it for when the button is pressed.
Also store the sound manager in a gameController that will be passed throughout the game. This would control the soundManager and have access to that. So sceneManager will also need a reference to gameManager.
Using a script that is just for player preferences (a controller if you will) is a better way to organize and contain any preferences for the users. Just better clarity and separation.
Example
SceneController Object Script
class SceneController {
GameObject muteButton;
void Start() {
muteButton = GameObject.FindWithTag("muteButton");
muteButton.AddListener(muteButtonCheck);
}
void muteButtonClick() {
if (PlayerPrefs.GetInt("playerMute")) {
// If 1 (on)
// Set sound off
PlayerPref.SetInt("playerMute", 0);
} else {
// It's 0 (off)
// Set sound on
PlayerPrefs.SetInt("playerMute", 1);
}
}
}

I need help organizing/planning a C# Tic Tac Toe Application

I'm a University Student who has experience in C++ and is new to C#. I wanted some feedback about how to approach building a C# Form application for a 5x5 Tic Tac Toe Game.
The specifics of the program require that a user enters a time for the player to make a move choice. Then the player selects whether they or the computer will go first. Then the player clicks a start button for the game to commence.
So far I figured I'd created a 'Move' class with a X and Y Coordinate representing a location on a game grid, and a 'Player' class that contains a list of 'Move' objects that they have made in the game. I was planning on adding a grid of clickable labels that would add a move to the players list of moves. As for the AI, I think it would be pretty easy to create an algorithm to block the human player from completing a row, but I'm not sure what data structure would be most efficient for this. Perhaps I'm thinking about it all wrong to begin with.
Any thoughts?
In the UI, I will use a 5 * 5 TableLayoutControl with a Button in each cell. You can set the FlatStyle for these button to Flat for the look.
Now, as far as maintaining a model is concerned, I will just have a single class to represent players. Something like this:
class Player : INotifyPropertyChanged
{
List<Point> _selectedCells = new List<Point>();
public List<Point> SelectedCells
{
get
{
return _selectedCells;
}
set
{
if (value != _selectedCells)
{
_selectedCells = value;
RaisePropertyChange(new PropertyChangedEventArgs("SelectedCells"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChange(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
}
Now, there will be 2 instances of this class. One for human and one for computer. On button click, you can set SelectedCells property. Now, changing this property will raise PropertyChanged event. a handler can be placed that checks for the victory.
If user has not won yet, generate computer move and set same property on computer instance. Again it will check for victory.
As and when a user wins, you can display appropriate message. You can add a string property Name to Player class to ease the victory message display mechanism.

Categories