Process.Start opens too many browsers in XNA game - xna

I'm creating a game in XNA that runs on a PC.
On the splash screen, the user has three options. If they press "Enter" the game will begin, if they press "M" they'll go to the Help menu and if they press "W" I want that to take them to my website.
I'm using Process.Start to open the browser to my website.
The problem is that when I press "W", sometimes it will open 1 browser with the website. However, most of the time it will open anywhere from 3 - 7 browsers simultaneously.
Why is it opening multiple browsers simultaneously?
How do I make it open only 1 browser when "W" is pressed?
Here is my code. I haven't built my website yet, so I'm using yahoo.com as the destination:
private void UpdateSplashScreen()
{
KeyboardState keyState = Keyboard.GetState();
if (gameState == GameState.StartScreen)
{
if (keyState.IsKeyDown(Keys.Enter))
{
gameState = GameState.Level1;
explosionTime = 0.0f;
}
if (keyState.IsKeyDown(Keys.M))
{
gameState = GameState.HelpScreen;
}
if (keyState.IsKeyDown(Keys.W))
{
Process.Start("IExplore.exe", "www.yahoo.com");
}
}
Thanks,
Mike

A common way to handle this is to always track the keyboard state from the previous frame. If a key wasn't down on the previous frame, but is down this frame then you know it was just pressed. If the key was down on the previous frame then you know it's being held down.
// somewhere in your initialization code
KeyboardState keyState = Keyboard.GetState();
KeyboardState previousKeyState = keyState;
...
private void UpdateSplashScreen()
{
previousKeyState = keyState; // remember the state from the previous frame
keyState = Keyboard.GetState(); // get the current state
if (gameState == GameState.StartScreen)
{
if (keyState.IsKeyDown(Keys.Enter) && !previousKeyState.IsKeyDown(Keys.Enter))
{
gameState = GameState.Level1;
explosionTime = 0.0f;
}
if (keyState.IsKeyDown(Keys.M) && !previousKeyState.IsKeyDown(Keys.M))
{
gameState = GameState.HelpScreen;
}
if (keyState.IsKeyDown(Keys.W) && !previousKeyState.IsKeyDown(Keys.W))
{
Process.Start("IExplore.exe", "www.yahoo.com");
}
}
I usually create a KeyPressed function which cleans things up a bit.
bool KeyPressed(Keys key)
{
return keyState.IsKeyDown(key) && !previousKeyState.IsKeyDown(key);
}

The code you are using runs about 60 times a second; you may only press your key down for 100ms or so but in that time it checks to see if W is pressed down about 7 times. As such, it opens a large number of browser windows.
Try recording a timestamp (using DateTime.Now) of when you open the browser and then check that a certain time has elapsed (~2 secs?) before allowing another window to be opened. Or, create a boolean flag that is set false by opening the browser, so the browser can be opened only once.

Thanks guys, that's what the problem was.
Callum Rogers solution was the easiest:
I declared a boolean:
bool launchFlag = false;
Then checked it and set it to true after the website launched.
private void UpdateSplashScreen()
{
KeyboardState keyState = Keyboard.GetState();
if (gameState == GameState.StartScreen)
{
if (keyState.IsKeyDown(Keys.Enter))
{
gameState = GameState.Level1;
explosionTime = 0.0f;
}
if (keyState.IsKeyDown(Keys.M))
{
gameState = GameState.HelpScreen;
}
if (keyState.IsKeyDown(Keys.W))
{
if (launchFlag == false)
{
Process.Start("IExplore.exe", "www.yahoo.com");
launchFlag = true;
}
}
}
I held the W key down for 30 seconds and it launched just 1 browser!
Thanks,
Mike

Related

UWP: WebView using the Mouse Forward and Backward Buttons

I'm developing a UWP-App with a WebView inside. At the WebView I want to use the forward and backward buttons of the mouse to navigate forward and backward. At default the WebView doesn't support it. (a normal browser does)
So I've found the PointerPressed Event and in this event I can check if the pointer-device is the mouse and if the pointer-properties are IsXButton1Pressed or IsXButton2Pressed. If I implement it on other usercontrols it works perfectly. But on the WebView usercontrol it doesn't work.
That's how I implemented it on other usercontrols:
private void Page_PointerPressed(object sender, PointerRoutedEventArgs e)
{
PointerPoint currentPoint = e.GetCurrentPoint(this);
if(currentPoint.PointerDevice.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
{
PointerPointProperties pointerProperties = currentPoint.Properties;
if(pointerProperties.IsXButton2Pressed)
{
if (grd_content.Children.Count == 1 && grd_content.Children[0] is Interfaces.IWebNavigation)
{
Interfaces.IWebNavigation iWebNav = (Interfaces.IWebNavigation)grd_content.Children[0];
e.Handled = iWebNav.GoForward();
}
}
else if(pointerProperties.IsXButton1Pressed)
{
if (grd_content.Children.Count == 1 && grd_content.Children[0] is Interfaces.IWebNavigation)
{
Interfaces.IWebNavigation iWebNav = (Interfaces.IWebNavigation)grd_content.Children[0];
e.Handled = iWebNav.GoBackward();
}
}
}
}
How can I implement the mouse forward and backward button on a WebView usercontrol?

How to set up GCController valueChangeHandler Properly in Xcode?

I have successfully connected a steel series Nimbus dual analog controller to use for testing in both my iOS and tvOS apps. But I am unsure about how to properly set up the valueChangeHandler portion of my GCController property.
I understand so far that there are microGamepad, gamepad and extendedGamepad classes of controllers and the differences between them. I also understand that you can check to see if the respective controller class is available on the controller connected to your device.
But now I am having trouble setting up valueChangeHandler because if I set the three valueChangeHandler portions like so, then only the valueChangeHandler that works is the last one that was loaded in this sequence:
self.gameController = GCController.controllers()[0]
self.gameController.extendedGamepad?.valueChangedHandler = { (gamepad, element) -> Void in
if element == self.gameController.extendedGamepad?.leftThumbstick {
//Never gets called
}
}
self.gameController.gamepad?.valueChangedHandler = { (gamepad, element) -> Void in
if element == self.gameController.gamepad?.dpad {
//Never gets called
}
}
self.gameController.microGamepad?.valueChangedHandler = { (gamepad, element) -> Void in
if element == self.gameController.microGamepad?.dpad {
//Gets called
}
}
If I switch them around and call self.gameController.extendedGamepad.valueChangeHandler... last, then those methods will work and the gamepad and microGamepad methods will not.
Anyone know how to fix this?
You test which profile is available and depending on the profile, you set the valueChangedHandler.
It's important to realise that the extendedGamepad contains most functionality and the microGamepad least (I think the microGamepad is only used for the AppleTV remote). Therefore the checks should be ordered differently. An extendedGamepad has all functionality of the microGamepad + additional controls so in your code the method would always enter the microGamepad profile.
Apple uses the following code in the DemoBots example project:
private func registerMovementEvents() {
/// An analog movement handler for D-pads and movement thumbsticks.
let movementHandler: GCControllerDirectionPadValueChangedHandler = { [unowned self] _, xValue, yValue in
// Code to handle movement here ...
}
#if os(tvOS)
// `GCMicroGamepad` D-pad handler.
if let microGamepad = gameController.microGamepad {
// Allow the gamepad to handle transposing D-pad values when rotating the controller.
microGamepad.allowsRotation = true
microGamepad.dpad.valueChangedHandler = movementHandler
}
#endif
// `GCGamepad` D-pad handler.
// Will never enter here in case of AppleTV remote as the AppleTV remote is a microGamepad
if let gamepad = gameController.gamepad {
gamepad.dpad.valueChangedHandler = movementHandler
}
// `GCExtendedGamepad` left thumbstick.
if let extendedGamepad = gameController.extendedGamepad {
extendedGamepad.leftThumbstick.valueChangedHandler = movementHandler
}
}

How to add a timer?

I have a working Unity script with multi-touch that will detect the touch, see if the touch has hit a collider (part of a gameObject), then checking to see if it is the right collider, and destroying it. Here is the working code:
using UnityEngine.UI;
using UnityEngine;
using System.Collections;
public class GameController : MonoBehaviour
{
void Update () // Updates every frame
{
if (Input.touchCount != 0) // Triggered by a touch
{
foreach (Touch touch in Input.touches) // Triggered as many times as there are touches.
{
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(touch.position), Vector2.zero);
if (hit && touch.phase == TouchPhase.Began && hit.collider.gameObject.tag ==("Fish")) // Triggered if touch hits something, when touch just begins, and if the object hit was tagged as a "Fish"
{
hit.collider.gameObject.GetComponent<FishScript>().TappedOut(); // Fish script activated
}
}
}
}
}
This is the working code. Now I want to add a timer in there, and I want it to time the touch. I want to make it so if the player can tap, and move their finger over the fish and it will count, so long as the moved their finger over the fish in 1 second. Here is the script I wrote and need help with:
using UnityEngine.UI;
using UnityEngine;
using System.Collections;
public class GameController : MonoBehaviour
{
void Update () // Updates every frame
{
if (Input.touchCount != 0) // Triggered by a touch
{
foreach (Touch touch in Input.touches) // Triggered as many times as there are touches.
{
if (touch.phase == TouchPhase.Began)
{
float touchTimer = Time.time;
int i = touch.fingerId;
}
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(touch.position), Vector2.zero);
if (hit && hit.collider.gameObject.tag ==("Fish")) // Triggered if touch hits something, when touch just begins, and if the object hit was tagged as a "Fish"
{
hit.collider.gameObject.GetComponent<FishScript>().TappedOut(); // Fish script activated
}
}
}
}
}
This is all I have so far. I tried using a return statement, and that did not work in the Void Update() function. I tried making another function with a while loop that would wait until each frame finished before going through another loop. That did not work. Will this idea work?
Here is a simple timer in Unity. Put CheckTimer() on your Update() method.
private double counter = 0.000d;
public double time = 2.000d; // How many seconds you want your timer to run
void CheckTimer()
{
counter+= Time.deltaTime;
if (counter >= time)
{
// Time has passed
counter = 0.000d;
// Do stuff here..
}
}
In your case, you may set a bool to true when your condition is met, then make it so that CheckTimer() only runs when the condition is true.
To fix this make the timer a global variable by instantiating it at the top and doing as follows
using UnityEngine.UI;
using UnityEngine;
using System.Collections;
public class GameController : MonoBehaviour
{
public float timer;
public float duration;
void Start(){
duration = 1; //you can set this in code or in your hierarchy in Unity
}
void Update () // Updates every frame
{
if (Input.touchCount != 0) // Triggered by a touch
{
foreach (Touch touch in Input.touches) // Triggered as many times as there are touches.
{
if (touch.phase == TouchPhase.Began)
{
timer = Time.time + duration;
}
if(Time.time < timer){
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(touch.position), Vector2.zero);
if (hit && hit.collider.gameObject.tag ==("Fish")) // Triggered if touch hits something, when touch just begins, and if the object hit was tagged as a "Fish"
{
hit.collider.gameObject.GetComponent<FishScript>().TappedOut(); // Fish script activated
}
}
}
}
}
}
I don't have the rest of your code to ensure this works but the logic behind it does. You want to set your timer to the current time plus a given duration. If the current time is less than the timer you have set when the player does something, then you know they did their action before the time reached the timer. Does that make sense?
I know I'm not suppose to take up comment spaces by saying thanks, but thanks Jonnus. The only thing that baffles me now is how I didn't think of this sooner. Anyways, here is the take away code for anybody who needs help with a multi-touch script.
using UnityEngine.UI;
using UnityEngine;
using System.Collections;
Private float timer; // Control variable
Public float duration; // How long you want your touch to be valid
Void Start ()
{
duration = 1; // Also adjustable in the interface
}
Void Update ()
{
if (Input.touchCount != 0) // Triggered by a touch
{
Foreach (Touch touch in Input.touches) // Triggered as many times as there are touches
{
if (touch.phase == TouchPhase.Began)
{
timer = Time.time + duration;
}
RaycastHit2D objectPlayerTouched = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(touch.position), Vector2.zero);
// var objectPlayerTouched is the 2DCollider for whatever the player tapped on.
if (objectPlayerTouched != null && Time.time < timer) // Triggered if player taps an object and time is still valid
{
objectPlayerTouched(destroy); // This means whatever object the player tapped is now destroyed
}
}
}
}
Once again, a big thanks to Jonnus. I thought this would be a lot more complicated. Also, don't do what I did and forget to set the duration in the interface and end up spending 10 minutes looking for a problem... Trust me it's annoying.

Disable eventlistener temporarily till animation completes

I'm working on a basic flash fight game. I'm not a developer so i'm new to actionscript except that i have some background knowledge about coding from my course.
The problem is-
There are about 6 fighting moves and i want to disable all 6 key_down events till the animation completes. And all 6 animations have different time frames. Can some1 just help me out with this?
stage.addEventListener(KeyboardEvent.KEY_DOWN, enterKeyHandler);
function enterKeyHandler(event:KeyboardEvent):void {
if (event.keyCode == Keyboard.B) {
gotoAndPlay(252);}
if (event.keyCode == Keyboard.V) {
gotoAndPlay(259);}
I have put down only 2 of them but there 6 in total.
I would use a public static flag , ex:
keyboardDisabled:Boolean = false;
While you play your animations you could set this to true, and inside the function which listens to keyboard events just check if keyboard is disabled and return right away.
Some code would look like
public static var keyboardDisabled:Boolean = false;
stage.addEventListener(KeyboardEvent.KEY_DOWN, enterKeyHandler);
function enterKeyHandler(event:KeyboardEvent):void {
if ( keyboardDisabled )
return;
if (event.keyCode == Keyboard.B) {
gotoAndPlay(252);}
if (event.keyCode == Keyboard.V) {
gotoAndPlay(259);
}
Then in the frame where your animation begin
keyboardDisabled = true;
And on animation end
keyboardDisabled = false;

Control sound to only play once in XNA

I use a sound each time a key is pressed to fire a missile. But it doesn't sound nice. I guess it's because the the sound is repeated so many times while the key is pressed down and that the code is within the Update method. I'm looking for a simple solution to just play the sound once when key is pressed? (I have tested to use a boolean variable to be true the first time and then false after det the sound has been played, but this didn't worked well because, when and where should I set it to true again) Help is preciated!
// Fire
if (keyboardState.IsKeyDown(Keys.Space))
{
missile.launchMissile(spaceship.spaceshipPosition, spaceship.spaceshipDirection);
soundExplosion.Play();
}
EDIT New code that isn't working!?
KeyboardState keyboardState = Keyboard.GetState();
KeyboardState prevKeyboardState;
prevKeyboardState = keyboardState;
keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.Space) && prevKeyboardState.IsKeyUp(Keys.Space))
{
missile.launchMissile(spaceship.spaceshipPosition, spaceship.spaceshipDirection);
soundExplosion.Play();
}
Store your previous keyboard state as well
KeyBoardState prevKeyboardState;
then in your update
prevKeyboardState = keyboardState;
keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.Space) && prevKeyboardState.IsKeyUp(Keys.Space))
{
//your code
}
You're basically just triggering the sound tons of times every second making it sound awful.

Resources