How can I decrement lives on collision, using XNA with C#? - c#

I have an assignment for my computer graphics class, were we have to alter a game code. The class itself is entirely about theory, so we pretty much have to figure out the code for ourselves and I've never programmed in C#, so sorry for any ignorance on my part.
Whenever my player sprite is hit by a box, I want the lives variable to decrement by 1. However, whenever it gets hit it just keeps going down. I understand why this is happening, but I don't know how to stop it.
This is the code that checks wether the two objects have collided.
if (b.BoundBox.Intersects(player.BoundSphere)){
player.hit = true;
}
In the update function for the player I have:
if(hit){
lives -= 1
}
How can I make it decrements only once, instead of constantly?

This is happening because it will constantly be detecting that it is colliding, as long as part of one of the objects is inside the other it will say that it is colliding.
What you can do to work around this is when the objects collide, set a boolean value that says the objects have collided and start a timer for however many seconds. While the boolean value is set to true, when the objects collide it will not decrement the lives but if it is false it will decrement. Once the timer is up, set the value to false so they can keep colliding. This gives the object time to leave the 'innards' of the other object.
Edit:
This is a very simple fix and might not work in your situation (as i don't know the rules of the game). A more complete solution would be to push the objects apart just enough that they are no longer colliding or predict one update tick ahead where each object will be and prevent them from ever actually colliding.

You don't need a timer for this problem, just declare another bool that keeps track if you've updated lives.
if (b.BoundBox.Intersects(player.BoundSphere) && !player.hit)
{
player.hit = true;
player.updated = false;
}
In your player's update:
if (hit && !updated)
{
lives -= 1
updated = true;
}
However, if you want to use a counter simply declare a:
TimeSpan timer = new TimeSpan(0, 0, x); //where x is how many seconds you need
and then in the Update method:
timer -= gameTime.ElapsedGameTime;
if (timer <= TimeSpan.Zero)
{
// do what you want
}

Related

Better way to check when variable equals to another value

I have a variable that I need to check frequently when my game is running. To simplify this, the check is: if (score >= achievement1) {do something}.
It seemed overkill to put this check in the Update() function which is called every frame;
So instead, I call the InvokeRepeating function in the Start (); function:
InvokeRepeating ("checkscoreforachievement", 0f, 2f);
Is this smart or is there a better way doing this? End result should be that within a few seconds after achieving a certain score, the achievement is triggered.
The reason I'm asking is that there are a few more things I need to do regularly when my game is running, so I'll end up with quite a few of these processes. Wondering if that isn't too much of a resource drain. Can't find good documentation on this subject.
No, InvokeRepeating is not better in this case.
It's not better because you are calling that function every 2 seconds which means that when score >= achievement1 evaluates to true, it will take about 2 seconds to detect that. Also, InvokeRepeating uses reflection which is slow. There is no advantage of using it here. Using the Update function like you are currently doing it is totally fine.
A much more better solution than using the Update function would be to check if score >= achievement1 only when score is changed with auto property.
public int achievement1 = 0;
private float _score;
public float score
{
get
{
return _score;
}
set
{
if (_score != value)
{
_score = value;
if (_score >= achievement1)
{
//Do something
}
}
}
}
This will only do the check when the score variable is set or changed instead of every frame but the Update code is fine.
Some other users have pointed this out similar things already, but essentially when the score is changed, call a function of your own to check. Don't invoke repeating or use update because honestly, it's just unnecessary to do it so infrequently or so frequently respectively.
Literally set it that when your score is incremented or decremented (changed in any way) you call the function to check.
You could also create an Array of achievements, and check the index before you even call the function to display/update the achievement:
if(arrayname[i] != "Unlocked"){
//Call function;
}

Does 'yield return new WaitForSeconds(4.0f)' have to charge?

I am making a First Person Shooter.
I want that my gun reloads, there plays an animation and after 4 seconds the number of bullets will be displayed. But sometimes it does and sometimes it doesn't wait and displays the bullets immediately without playing the animation.
IEnumerator waitForReload()
{
if (reloadNow==true && !gun.GetComponent<Animation>().IsPlaying("Reload"))
{
animator.SetInteger ("Anumber", reload);
yield return new WaitForSeconds (4.0f);
reloadNow = false;
displayBullets ();
}
}
I would advise against using the Animation component, you'll be after the Animator. They do similar things, except the Animator is Unity's newer and more improved version. Grabbing the Animation component and checking IsPlaying won't tell you whether the animation is playing, as the animation is being played through the Animator component.
First thing to check is your co-routines, how often are you firing them? The logic within is sound, however, you would ideally not start the co-routine again if you are reloading.
The yield in the co-routine is where the magic happens. Each time you yield, the function remembers it's location, so when you execute the function again it will pick up from where you left off. Each time you call StartCoroutine, a new routine is created.
So, if you accidentally start the co-routine again, you'll have multiple instances of it running, which is why it is potentially glitching out in certain places.
I'd recommend whacking some debugs in, put one in where you start the co-routine and one when you finish. If your console is getting spammed, then you know that you're starting it incorrectly and would either have to stop it from firing when it shouldn't or by starting the co-routine, and ending it if your checks say no.
if(reloading == false)
{
reloading = true;
StartCoroutine(waitForReload());
}
else
{
//do nothing
}
IEnumerator waitForReload()
{
//your custom reload logic here
reloading = false;
//set reloading to false so we can reload again later, after the time is up in your case
}
Something along those lines should give you the intended result.
For the yield command, here's a reference
https://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx
For the animator component:
https://docs.unity3d.com/ScriptReference/Animator.GetCurrentAnimatorClipInfo.html
This'll give you back the current animation clip that is playing, so you can check names that way.
Hopefully this'll lead you in the right direction.
I believe the problem occurs because your coroutine runs more than once, try this (assuming your animation is 4 seconds long)
IEnumerator waitForReload()
{
if (reloadNow)
{
animator.SetInteger ("Anumber", reload);
reloadNow = false;
yield return new WaitForSeconds (4.0f);
displayBullets ();
}
}
or preferably you can call the function that displays the bullets at the end of your animation

Avoid to use 'Update'?

I have a seperate script of time which I use to show time in my scene. It contains hour and minute and seconds variable.I want to do some specified work e.g., code execution on specified time and currently i am doing something like this. in Update. I am running a function which check continously check time variable in order to run an animation.
void Update()
{
checkTrainArriveTime();
}
void checkTrainArriveTime()
{
if (timeManager.GetComponent<Scale2>().hour == trainArriveTimeHour && timeManager.GetComponent<Scale2>().min == trainArriveTimeMin
&& isTrainArriveConditionExecute)
{
isTrainArriveConditionExecute = false;
PlayAnimationClip("Start");
}
else if (timeManager.GetComponent<Scale2>().min != trainArriveTimeMin)
{
isTrainArriveConditionExecute = true;
}
}
As Time will match this function will play the animation. Now I have 50 script attached to 50 different game Object. It is
working fine but It definitely not the right way to use Update Event. In my code, It is necessary to check time on every frame and
extra load on update. Is there any efficient way to do this Job?.
I can see your struggle. You are right, it is definitely not the best way forward.
The best option I can see here would be creating Animation Manager which is a singleton instance (there is only one instance allowed per application).
I would suggest moving your animation triggering logic to an Update method of AnimationManager.
Once you have done that. You will be able to access its instance calling AnimationManager.getInstance() method.
Next step is creating internal registry that would be nothing else than just a list of your registered game objects that you want to trigger animation for.
I don't know what exactly is your timeManager but I can imagine it is probably an instance of TimeManager controller that you drag and drop onto your public timeManager property. Consider turning it into singleton as well or at least moving assignment of timeManager.GetComponent<Scale2>() into Awake() method.
It is important to not to call GetComponent() method from inside of Update()', as it has an impact on performance.GetComponent` is quite expensive to call.
Hope it helps.

XNA: How to measure the amount of time a key is held down for?

I'm trying to make a jumping mechanism in my game which will work something like this:
// velocity.Y is the velocity of the sprite I want to jump
if (keystate.IsKeyDown(Keys.W))
{
velocity.Y = 3 - (time elapsed since start of jump);
}
I thought this might be a simple and elegant solution to making my sprite jump but if it is not possible like this just say so and it's back to the drawing board.
I would suggest not connecting the physics so directly to the player input, it's not a very extendable architecture.
Have an interface which defines physics properties such as velocity which is implemented by your character object. When the player presses the up-key you should check if the player is on the ground, if they are then set their acceleration to move up. Then have a physics system iterate through a list of every object which implements the physics interface applying gravity and other forces before moving the entities around. This way you can use the same physics code for every entity in your game.
I would also suggest not connecting keyboard input directly to the movement of the player. You can have an interface called 'ICharacterController' which defines a 'nextInstruction' method which returns 'CharacterInstructions' which defines various actions characters can take such as jumping and moving, this can be implemented by an input class. Your character class then holds a reference to a CharacterController so it just calls nextInstruction, this way the character can be controlled by Player Input, AI, or through network communication but still share the same behavior as the player.
Game Coding Complete is a brilliant book to read if you're serious about game programming.
I can also recommend Game Engine Architecture
As you're using XNA you should consider using Game Components
XNA doesn't have built-in methods to detect a press vs. a press-and-hold; it is only able to tell you if the key is currently being pressed.
What you need to do, then, is to store two KeyboardState-s, "Old" and "Current". Once you have this, you are able to detect when a keypress starts (old.isKeyDown == false && current.isKeyDown == true; ) and when it ends (old.isKeyDown == true && current.isKeyDown == false;
So once you have this, it's a simple matter to record a "jumpStart" variable based on the GameTime when you detect the keypress, and a "jumpEnd" variable from when you detect the key release.
If you want to base the duration of a jump on the amount of time the key is held down, you may be better served by setting up an upper limit, afterwhich further holding down of the key has no effect.
not if that what you are looking for in another words if the velocity function is executing while you hold the button but ou can use stopwath to measure that
Stopwatch stopWatch = new Stopwatch();
if (keystate.IsKeyDown(Keys.W))
{
velocity.Y = 3 - (time elapsed since start of jump);
stopWatch.Start();
}
if (keystate.IsKeyUp(Keys.W))
{
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
}
more here
http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2

Developing Games - How are things that take more than one game loop performed?

I'm using C#, but this is applicable to developing a game in any language.
Most games use a 'game loop', which would look something like this:
while (game is running)
{
UpdateEnvironment();
DrawEnvironment();
}
I'm struggling to understand how things which would take more than one game loop fit into the equation. For example, making a ball of energy float from one tile to another. Or having a player move one tile (not jump from tile to tile but animate to it).
The best thing I have come up with is taking the time elapsed since the last loop, and passing it to the object / method so it can do its thing. But that makes it hard to do things such as:
AI.MoveTo(10, 20); // Pathfind, then walk the path to this tile.
Player.Shoot(); // Shoot a bullet, and detect collisions and update along the way.
Where can I find more information on 'performing events which take more than one game loop to accomplish'?
One way to do it is to store the complete pending action and then have the game loop perform only a little bit of it. The game objects referenced from the action know the state they are in, so the next bit to perform is known. While there is still something left to do, the action is added back to the queue of pending actions to be performed in the next loop, and when the action is complete, it is no longer added back.
So in your MoveTo example, the action to store is the move to 10, 20 and every time across the game loop, the AI is moved a little bit towards it. Your Shoot example is probably better to describe as the bullet traveling in a certain direction, and then whatever it hits determines whether the action is continued or not.
I haven't done game development, so I don't know whether this is how it's done in that field, but this is the way I would do something like this in an event-based system.
Actually, what you said about using the elapsed is fairly accurate. If you're familiar with C#, and aren't already doing so, I would highly recommend you look into either XNA or if you're willing to spend a little money, Dark GDK .NET by "TheGameCreators".
Anyway, the idea is that for each game loop, you update any "live" objects using the elapsed time since the last update. "Live" objects being anything that is still considered active and needs updating, (e.g., enemies, players, bullets in mid flight, explosions that are still going off, etc). You determine what the next state, position, health, etc each object should have based on the elapsed time, collisions, damage from fire, etc and then implement that next state. Finally, you then call the draw process for each of these objects, and render them in their new states.
For something like a player shooting, here is something you could do. Note, this is more pseudo code than anything. Hope it gives you an idea.
//Generic Game Class
public class MySweetGame : Game
{
Player _player = new Player(this);
List<Bullet> _bullets = new List<Bullet>();
public List<Bullet> AllBullets()
{
get { return _bullets; }
}
public void Update()
{
//You would obviously need some keyboard/mouse class to determine if a click took place
if(leftMouseButtonClicked)
{
_player.Shoot();
}
//This would be assuming you have an object collection or array to hold all the bullets currently 'live' like the above '_bullets' collection
//This is also assuming elapseGameTime is some built in game time management, like in XNA
foreach(Bullet blt in _bullets)
{
blt.Update(elapsedGameTime);
}
}
}
//Generic Player Class
public class Player()
{
Vector2 _position = new Vector2(0,0);
int _ammunition = 50;
MySweetGame _game;
public Player(MySweetGame game)
{
_game = game;
}
public void Shoot()
{
if(_ammunition > 0){
_game.AllBullets.Add(new Bullet(50, _position));
_ammunition--;
}
}
}
//Generic Bullet Class
public class Bullet()
{
float _metersPerSecond = 0;
Vector2 _position = new Vector2(0, 0);
public Bullet(float metersPerSecond, Vector3 position)
{
_metersPerSecond = metersPerSecond;
_position = position;
}
//Here is the meat you wanted
//We know the speed of the bullet, based on metersPerSecond - which we set when we instantiated this object
//We also know the elapsedGameTime since we last called update
//So if only .25 seconds have passed - we only moved (50 * .25) - and then update our position vector
public void Update(float elapsedGameTime)
{
distanceTraveled = metersPerSecond * elapsedGameTime;
_position.x += distanceTraveled;
}
}
You probably wouldn't use events; rather, MoveTo or Shoot should be thought of as a change in state. Your AI object would need a state consisting of variables like this:
class AI
{
StateEnum State; //Idle, Moving, Attacking, Dying, etc.
PointF Location;
PointF Velocity;
PointF Destination;
In your MoveTo method, you would need to set the object's state -- something like:
void MoveTo(x, y)
{
Destination = new PointF(x, y);
Velocity = new PointF(0.5, 0);
State = StateEnum.Moving;
}
Then in its Update method, you would update the location.
void Update()
{
switch (State)
{
case StateEnum.Moving:
Location.Offset(Velocity); //advance 0.5 pixels to the right
break;
default:
break;
}
}
}
That method would be called from the game loop based on some timer (e.g. 60 ticks per second), so in effect, the object is moving 30 pixels per second. And if it has animation frames, simply count down with the ticks and change the frame as needed.
As for pathfinding, to move from tile to tile, you could update the velocity at each tile so that the object is moving in the desired direction.
Apart from the solutions by WesleyJohnson and Gannon, you can also use a task based approach.
WesleyJohnson's and Gannon's solution has less complexity which is a good thing especially when the behaviour of your game's actors are statically defined. Like with a simple shooter game. But when you want the behaviour to be defined dynamically through scripting or when your actors have complex behaviours you may want to externalise behavioural management.
Because else your actors' update functions have to have a complex state management.
A common approach would be to have a base class called Task (or Process or Job)
And specific longer running tasks subclass Job. For instance you can have a MoveActorTask, PlayAnimationTask etc. With result codes and marks whether they are finished, you can also chain Tasks in a way that they are executed one at a time waiting for the former to be finished by using composite tasks
Here is what we use, slightly edited for better reading and stripped from some advanced options that may confuse else:
class Task
{
public:
/**
* Constructor.
*
* #param isDiscardable Set this true, if the Task's goal can be reached in a single step.
* For instance if a Task is supposed to slowly close a window by fading
* its alpha to 0, then it is discardable, and Task#discard will just finish
* the process by closing the window.
*
* #param destroyWhenDone Set this to true, when the TaskScheduler shall delete the
* Task, after execution is finished. This should usually be the case, but
* sometimes it is sensible to pool a number of Jobs for reuse.
*/
Task(bool isDiscardable,
bool destroyWhenDone);
virtual ~Task();
/**
* This is the function in which the Task is supposed to do whatever it is supposed to do.
* This function is called by the TaskScheduler at most once per frame. The frequency depends
* on the Job's priority given with TaskScheduler#addTask.
* #param time the time source time, since the last call of this function.
* #return true, when the Task is done, false else. If false is returned, the Task will be
* rescheduled for another execution.
*/
virtual bool execute(Time time) = 0;
virtual TimeSource::TimeSourceType getTimeSource() const = 0;
/// Returns whether the Task can be removed from the queue by the scheduler,
bool isDiscardable() const;
/// Returns true, if the Task shall be deleted, if the Job is finished. Returns false else.
bool destroyWhenDone() const;
/// Finish whatever the Task is doing. It won't get a chance to continue.
/// Overloaded functions must *not* call this implementation.
virtual void discard();
protected:
bool mIsDiscardable;
bool mDestroyWhenDone;
};
The Tasks are managed by a TaskScheduler. Each frame the TaskScheduler calls the task's execute function for all tasks (Round robin) or you can have a different scheduling strategy.
Consider how operating systems allow multiple programs to run on a single processor:
Program 1 is running
Program 1 is interrupted
Program 1's state (contents of CPU registers and such) is saved by the kernel
Program 2's state is loaded by the kernel
Program 2 resumes
This "interrupt/save/restore/resume" approach is a "worst-case" option for tasks that are really hard to break up into parts. At one point (perhaps based on how long a task has been running), you save all of the variables the task needs, and stop running the code. Later on, you can restore the state and resume the code.
However, often it is possible to design your system in a way that reduces the need to resort to something like this. For example, designing animations so that they can be processed one frame at a time.

Categories

Resources