How to toggle a Key Press - xna

I have the issue. I have programmed my Shoot em up and i came to dead end when i have to ask so many questions in here
if(key State.IsKeyDown(Keys.Space))
{
Shoot Bullets();
}
Problem is when i Hold Space bar it shoots....i do not want to hold Space bar for 30 minutes just to end the level. I wanna make it to toggle.
What is best and least coded way to do it.
I did spend like 2 days trying to figure this out and i can't...help would be appreciated

As #folkol suggested:
Include:
bool Shoot;
And initialize as:
Shoot = false;
What you check for input
if(key State.IsKeyDown(Keys.Space)) // Need to flip on key release
Shoot = !Shoot // Flips the variable
And in your Update() Method:
if(Shoot)
Shoot Bullets(); // Shoots
Notice that this will flip the Shoot Variable a lot. You will need to create an oldState value and flip on key release.

Instead of "Shoot Bullets", flip the value of a boolean variable. And use that variable as the indicated for whether you should fire some bullets in any given game loop iteration.
Something like this:
public class MyGame : Microsoft.Xna.Framework.Game
{
/* Some other state */
bool isShooting = false;
/* Some other methods */
protected override void Update(GameTime gameTime)
{
/* Some other code */
if(keyState.IsKeyDown(Keys.Space))
{
// Flip the boolean value. If it was failse, set it to and vice versa
isShooting = !isShooting; true.
}
if(isShooting)
{
Shoot.Bullets();
}
}
}

I added another short but correct example for you, some of the other answers were pretty much there, but had some errors in them.
KeyboardState kbState;
bool isShooting;
protected override void Update(GameTime gameTime)
{
KeyboardState lastkbState = kbState;
kbState = Keyboard.GetState();
if (kbState.IsKeyDown(Keys.Space) && lastkbState.IsKeyUp(Keys.Space))
{
isShooting = !isShooting;
}
if (isShooting)
{
Shoot.Bullets();
}
}
Your other answer I don't have the reptuation to add a comment on doesn't work because you made the previous and the current keyboard state properties equal the same thing.

Related

How do I delete a GameComponent from Game.Components?

Basically my game is to stop the rocks falling from the sky using a plank.
I'm not sure what is not functioning correctly, but here is my code:
In the RockManager class
public void CheckForPlankCollision(Plank plank)
{
foreach (GameComponent component in Game.Components)
{
if (component is FallingRock rock)
{
if (plank.Bounds.Intersects(rock.Bounds))
{
rock.HandleCollision();
Rectangle bounds = rock.Bounds;
}
}
}
}
In the Rocks class
public void HandleCollision()
{
//rockPosition = rockAfterImpactPosition; // I tried to move it offscreen
//rockPosition = Vector2.Zero; //I tried for any reaction
//this.Enabled = false; // tried this
//Game.Components.Remove(this); //tried this
}
I'm also trying to implement a scoring system. (add 1 point if the rock hits the plank, subtract a point if it hits the ground)
Try casting this as an IGameComponent or GameComponent object.
public void HandleCollision()
{
Game.Components.Remove((GameComponent)this);
}
Tell me if this works for you !
EDIT: You might also want to defer the deletion of your game object to later, when it isn't used by the foreach (GameComponent component in Game.Components) loop, which might have a lock on removing elements during that time.

Can't receive value from another class on XNA Framework C#

I have several classes on my project: Game1(main class(default)), Animation and Enemy:
public class Animation
{
public int currentFrameHit;
public Animation ()
{
}
public void Update(GameTime gameTime)
{
timeElapsedHit += gameTime.ElapsedGameTime.Milliseconds;
if (timeElapsedHit > 100)
{
timeElapsedHit = 0;
currentFrameHit = (currentFrameHit + 1) % 9;
}
}
}
How can i get value from variable in Animation class?
In Enemy class i can't receive this value from Animation. I tried that:
Animation animation = new Animation();
Console.WriteLine(animation.currentFrameHit);
But i'm getting null, however in main class Game1 i receive right values with same code.
The problem is that you're making a new Animation() without assigning it to anything. so it'll keep returning it's default value.
So far there isn't enough information given on what the number should be though. Do you have the Animation() class inside the Enemy Class, or do you find the Enemy Class within Animation()?
You need to reference to an existing animation value.
Create an instance in your desire class (here it is Game1) and don't forget to make it public.
public static Animation animationGame1 = new Animation();
Then in your second class:
In LoadContent(): reference it to Game1's variable:
Animation animationNewClass = Game1.animationGame1;
In Update(): do what you want to achieve:
Console.WriteLine(animationNewClass.currentFrameHit);
Hope this helps.

MKMapView setVisibleMapRect with completion?

I am having a heck of a time getting around some very annoying behavior in MapKit. Specifically, I want to show a popover annotation view after the map has animated to a certain visible region.
I can use mapView:regionDidChangeAnimated: to get a callback after the map transition (which I will call the "zoom"), but this only fires if the visible region actually changes.
You see the zoom happens in my app when an annotation (or its counterpart in a table view) is selected: I want to zoom the map to essentially focus on the selected annotation.
The problem is that if the map is already in the correct region, I will get no regionDidChange, and therefore no signal to show my popover view.
I am using variants of setVisibleMapRect: to actually perform the zoom. So I thought I was being smart by comparing the new and old MKMapRects to see if they are equal, and if so manually calling my callback.
The problem is it doesn't work! Even if I determine that the two MKMapRects are not equal, by means of MKMapRectEqualToRect, MapKit just sometimes decides it won't fire the regionDidChange event! Perhaps it has to be over a certain delta or something, I don't know.
So my question is: what the heck is the expected best practice for getting a guaranteed completion from setVisibleMapRect:?
Update: I'm now thinking this might have to do with the edgePadding argument which I am also using:
- (BOOL)vivoSetVisibleMapRect:(MKMapRect)mapRect edgePadding:(UIEdgeInsets)insets animated:(BOOL)animate {
BOOL equal = MKMapRectEqualToRect(self.visibleMapRect, mapRect);
NSLog(#"Map rects are: %#", equal ? #"equal" : #"NOT equal");
NSLog(#"%#\n\n%#", MKStringFromMapRect(self.visibleMapRect), MKStringFromMapRect(newRect));
[self setVisibleMapRect:mapRect edgePadding:insets animated:animate];
return !equal;
}
As you can see, the edge padding is not taken into account in the comparison, yet it is most likely having an effect on the finally computed mapRect.
Does anyone know how I can perform this test to properly take into account edgePadding?
Update 2: It's now looking like MKMapRectEqualToRect is wrong and therefore completely useless. Check out this log statement:
2016-03-16 17:06:30.841 Mobile[70089:6240786] Map rects are: NOT equal
{{42403042.3, 91858289.9}, {14878.4, 12832.6}}
{{42403042.3, 91858289.9}, {14878.4, 12832.6}}
They look pretty darn equal to me!! 😒
MapRects are defined using Doubles, and comparing Doubles can give unexpected behavior. My recommendation is to define your own comparison that compares to your desired tolerance. For instance, compare to the nearest integer value.
In Swift:
public extension Double {
func roundToInt() -> Int {
let value = Int(self)
return self - Double(value) < 0.5 ? value : value + 1
}
}
public func == (lhs: MKMapRect, rhs: MKMapRect) -> Bool {
if lhs.origin.x.roundToInt() != rhs.origin.x.roundToInt() {return false}
if lhs.origin.y.roundToInt() != rhs.origin.y.roundToInt() {return false}
if lhs.size.width.roundToInt() != rhs.size.width.roundToInt() {return false}
if lhs.size.height.roundToInt() != rhs.size.height.roundToInt() {return false}
return true
}
You can then do a comparison by typing
if mapRect1 == mapRect 2 {
...
}
It turns out MKMapRectEqualToRect is completely broken (at least on the simulator). Don't use it!!
I changed it to instead do a comparison on the strings returned by MKStringFromMapRect, as well as adjusting the map rect with mapRectThatFits:edgePadding: before the comparison and it now appears to be working correctly:
- (BOOL)vivoSetVisibleMapRect:(MKMapRect)mapRect edgePadding:(UIEdgeInsets)insets animated:(BOOL)animate {
MKMapRect newRect = [self mapRectThatFits:mapRect edgePadding:insets];
BOOL equal = [MKStringFromMapRect(self.visibleMapRect) isEqualToString:MKStringFromMapRect(newRect)];
[self setVisibleMapRect:newRect animated:animate];
return !equal;
}

How best would I store a variable that will be used multiple times throughout the execution of a method and will stay the same?

Say I'm handling a pan gesture with UIPanGestureRecognizer, and I want to know the initial point every time the function is called when the view is panned. So I save it into a variable and for each additional time that function is called I can just access this unchanging variable, as the original value I got it from (say, the first time the function is called I save its value) will be changed as the function gets called more.
Static variables don't seem to work as if I do the following:
static CGFloat originalImageTopPosition = CGRectGetMinY(self.imageBeingOverlayedScrollView.frame);
I get:
Initializer element is not a compile-time constant.
I could use a property, but if there were tons of cases where I needed things like this, it would seem like a poor choice to clutter up my list of properties with random saved values.
You can declare a static variable without initializing it (or initialize to zero or something), then in an initialization method set it.
well floats are a little tricker, generally you will use some sort of magic value, assuming that you will want 0 to be valid there is a little float trick you can use
static float blah = 0/0.f;
if (blah!=blah)
{
blah = 3.4;
}
basically you use a compile time constant that is a NaN, then NaN!=NaN... then you get to set at run time.
so for your case it would be...
static CGFloat originalImageTopPosition = 0.0/0.0;
if(originalImageTopPosition!=originalImageTopPosition)
{
originalImageTopPosition = CGRectGetMinY(self.imageBeingOverlayedScrollView.frame);
}
Edit - just thought of a less cryptic way...
static CGFloat * originalImageTopPositionPtr = NULL;
static CGFloat originalImageTopPosition = 0.0/0.0;
if(!originalImageTopPositionPtr)
{
originalImageTopPosition = CGRectGetMinY(self.imageBeingOverlayedScrollView.frame);
originalImageTopPositionPtr = &originalImageTopPosition;
}
and an even less cryptic way...
static BOOL originalImageTopPositionInited = NO;
static CGFloat originalImageTopPosition = 0.0/0.0;
if(!originalImageTopPositionInited)
{
originalImageTopPosition = CGRectGetMinY(self.imageBeingOverlayedScrollView.frame);
originalImageTopPositionInited = YES;
}
It depends on the situation. For your example of handling a pan gesture, you can assign the value to a local variable inside an if clause like this:
CGPoint point;
if (sender.state == UIGestureRecognizerStateBegan){
point = [sender locationInView:nil];
}
This will only be called once during a pan gesture, so you can use this point to do calculations during the panning stage of the gesture.

Actionscript, objects and event listeners

Say I have an object
var my_obj = new Object();
my_obj['key'] = value;
Is there a way to add an event listener to the value, like
my_obj['key'].addEventListener(Blah Blah);
I have a long(ish) list of buttons on the timeline (the layout is so different from section to section that just makes more sense to do on the timeline rather than trying to build the layouts via actionscript).
button1 = plays "frame label 1"
button2 = plays "frame label 2"
and so on....so I was just thinking of storing everything in an array
obj["button1"] = "framelabel1"
arr.push(obj);
Then I could just have one event handler for all of the buttons and use target to get the frame label value...
Yes, you can do exactly what you're asking in the exact way you've mentioned, here's an example:
var value:Sprite = new Sprite();
var my_obj = new Object();
my_obj['key'] = value;
So calling:
my_obj['key'].addEventListener(Event.ENTER_FRAME, _onEnterFrameHandler);
is exactly the same as calling:
value.addEventListener(Event.ENTER_FRAME, _onEnterFrameHandler);
If the value is an IEventDispatcher or extends EventDispatcher you can add a listener to it.
The question is rather obscure to me. My guess is that you need something triggered every time a value is set. If this is the case, then you have to create a custom class, and declare a getter-setter property there.
For instance:
package
{
import flash.display.Sprite;
public class TestAccessor extends Sprite
{
private var someVarValue:uint = 0;
public function TestAccessor()
{
super();
}
public function get someVar():uint
{
return someVarValue;
}
public function set someVar(value:uint):*
{
someVarValue = value;
// this is the place where someVar is set.
// do whatever else you like here,
// you may choose to dispatch an event from here if you need.
}
}
}
Back in AS1-AS2 era we had watch() and addProperty() for that purpose, but these times are long since gone. For good. :)

Resources