So I have a method that is suppose to make an an object move up rapidly. The code inside is :
b2Vec2 force;
force.Set(_body->GetLinearVelocity().x, _body->GetLinearVelocity().y+1.0f);
for (b2Body* b = _game.world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetUserData() == character)
{
b->SetLinearVelocity(force);
}
}
The code is not important, I want to know how I can stop this process after a few seconds or once it reaches a certain y point. because atm it runs out of the screen!
Regards.
Just test if the y position of the body is below the threshold you don't want it to cross:
for (b2Body* b = _game.world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetUserData() == character && b->GetPosition().y < 300)
{
b->SetLinearVelocity(force);
}
}
What you can do is create an nstimer for periodically calling the selector which has your code and put it in repeat mode.
this will go on forever.. so in order to stop it after a particular amount of time put this entire thing in a new method and call that method inside a new nstimer.
so basically a timer inside a timer.
Related
I've just started using gamemaker studio 2 and I've been scratching my head over this one for a while.
I need to be able to destroy a specific instance of my enemy object without using the collision event. Here is my current code:
In my player object:
if (sprite_index = spr_player_attack_left) {
if (obj_enemy.x > x - 25 && obj_enemy.x < x) {
obj_enemy.hp--;
}
}
//detect right
if (sprite_index = spr_player_attack_right) {
if (obj_enemy.x < x + 25 && obj_enemy.x > x) {
obj_enemy.hp--;
}
}
//detect up
if (sprite_index = spr_player_attack_up) {
if (obj_enemy.y > y - 25 && obj_enemy.y < y) {
obj_enemy.hp--;
}
}
//detect down
if (sprite_index = spr_player_attack_up) {
if (obj_enemy.y < y + 25 && obj_enemy.y > y) {
obj_enemy.hp--;
}
}
And in my enemy object:
if (hp <= 0) {
var attacked = instance_find(obj_enemy, this.id);
instance_destroy(attacked);
}
Currently there is only one instance of the enemy in the room that registers an attack, and when I attack that instance, all instances are destroyed, while I only want one to be destroyed.
Thanks in advance for any help!
The reason this is happening is because you are using the object index, and not an index of a specific instance. When you do:
<object_index>.<object_property> eg. obj_enemy.hp
Two things can happen:
If there is one instance currently active in the game, then that
instance's variable will be referenced.
If there are two or more instances, then GameMaker can't tell which one you want to reference.
The offending code here are the if statements:
if (obj_enemy.x > x - 25 && obj_enemy.x < x) {
obj_enemy.hp--;
}
The way you can rewrite them is:
with (obj_enemy) {
if (x > other.x - 25 && x < other.x) hp--;
}
The same goes for all of the other if statements as well. The with keyword acts as a loop here. You can read it as "go through each instance of obj_enemy and do the code between { ... }". To reference the instance outside the with statement we use other(in this example, other will be the player).
And for the code in the enemy object, you don't have to use instance_find at all. Actually the this.id part is completely invalid, unless you define this as an instance variable before that code runs.
Anyways, the correct version would be:
if (hp <= 0) {
instance_destroy();
}
The instance_destroy function destroys the instance that is currently in scope(in GMS2 or GMS1 Early Access, you can pass it an additional id of the instance you wish to destroy).
I have a separate stack in my program with this timer vector attached. When called, the stack pops an element out and the timer keeps track of how long it is out via user input. When the time reaches 0, the element is put back into the stack. I wanted to work through multiple timers so I tried to put them all into a vector and have them all decrement by one time unit when a function is called. Not totally clear on how vectors work so I do not know how to decrement all of a vector's values.
int wait(vector<int> &x){
std::vector<int>::iterator itr;
for(itr = x.begin(); itr < x.end(); itr++)
{ //psuedocode
//x[itr]--;
}
}
I just want to make sure I'm going in the right direction.
Here is how you can decrement all the values in the vector
int wait(vector<int> &x){
for(std::vector<int>::iterator itr = x.begin(); itr != x.end(); itr++)
{
(*itr)--;
}
}
or using C++11
int wait(vector<int> x){
for (int& i : x )
i--;
}
To decrease the value pointed by the iterator in the code, you can do -
for(itr = x.begin(); itr < x.end(); itr++)
{ //psuedocode
(*itr)--;
}
*itr returns the value being pointed by the iterator.
Im needing to use local variables but when i use them for a timer (decreases time until conditions are met) it doesnt work
for (int i = 0; i < Weapons.Count; i++)
{
if (Weapons[i].ItemType == 6)
{
if (standard.IsKeyDown(Keys.G))
{
Cannons.Add(new CannonFire(this));
}
}
else if (Weapons[i].ItemType == 7)
{
float Recharge = Weapons[i].Laser.Rate;
Recharge -= (float)gametime.ElapsedGameTime.Seconds;
if (standard.IsKeyDown(Keys.G) && Recharge < 0)
{
laser.Add(new LaserFire(this, new Vector3(Weapons[i].Laser.range, 1, 1) ));
Recharge = Weapons[i].Laser.Rate;
}
}
}
other relevant code is where im getting the rate from
public class LaserItem
{
float Damage;
float Range;
float Last;
float RechargeRate;
public float damage
{
get { return Damage; }
set { Damage = value; }
}
public float Rate
{
get { return RechargeRate; }
set { RechargeRate = value; }
}
public float Life
{
get { return Last; }
set { Last = value; }
}
it works without the timer but i cant have it like that because i dont want 300 lasers to be built every time someone hits the key. as far as i can tell the timer is set to the laser rate every frame so it never reaches 0 (this section it in the update function)
for this piece of code its fine but when i need it in a loop i have to use local variables;
From what I can understand, what you are doing in the code is that you're creating a new local variable with the value set to the recharge rate of the laser every single update, firing it when the time from the last update is longer than the recharge rate - this would occur only on a very slow update.
Taking into account the automatic Update (the main loop one) calling of XNA, what would help you is setting some class variable for the Weapon, e.g. RemainingRecharge and when you fire, set it to the recharge rate and substract the elapsed time every update until it reaches zero or less. The only difference from your code is that the recharge is moved to the class instance and thus preserved between updates.
Recharge isn't a reference or a pointer; it's a copy (as float and double are immutable types). So, assigning a value to Recharge at the end of the if() block does absolutely nothing. (I'd bet that it even gets removed by the compiler).
Try this:
else if (Weapons[i].ItemType == 7)
{
float recharge = Weapons[i].Laser.Rate;
recharge -= (float)gametime.ElapsedGameTime.Seconds;
if (standard.IsKeyDown(Keys.G) && recharge < 0)
{
laser.Add(new LaserFire(this, new Vector3(Weapons[i].Laser.range, 1,1)));
/// changed the the next line:
Weapons[i].Laster.Rate = recharge;
}
}
i figured it out, XNA has a TimeSpan thing you can use its easier to work with and you can tell it if it reaches a number reset and do what you want
I am totally new at this whole programming thing, and I really need help. So basically, I'm trying to make a healthbar that will increase or decrease depending on what button is clicked. I made a healthbar movieclip with 101 frames (I included zero) and put this in the actionscript layer of the movieclip:
var health:Number = 0;
if(health == 0)
{
gotoAndStop("1")
}
if(health == 1)
{
gotoAndStop("2")
}
if(health == 2)
{
gotoAndStop("3")
}
and on and on like so. Basically, on the stage itself, I have a button called fortyfiveup_btn that is commanded to do this:
var health:Number = 0;
fortyfiveup_btn.addEventListener(MouseEvent.CLICK, fortyfiveupClick);
function fortyfiveupClick(event:MouseEvent):void{
health = health+45
}
I quickly realized that both health variables, the one for the button and the one for the healthbar will not interact. How can I make it so if the button is clicked, the health goes to the relevant frame or percentage?
Thanks for any answers, and I appreciate all the help I can get :)
If the answer == yes to my comment you should do this:
You need to give the movieclip an instancename (perhaps lifebar) and from stage you can access the health inside the "lifebar" with lifebar.health.
So you need this inside your stage:
//You can delete the var health:Number = 0;
fortyfiveup_btn.addEventListener(MouseEvent.CLICK, fortyfiveupClick);
function fortyfiveupClick(event:MouseEvent):void{
//You can write this, too: lifebar.health += 45;
lifebar.health = lifebar.health+45;
}
You can even optimize your lifebar script, don't use 101 times the if(health == x) you can use this, too:
gotoAndStop(health + 1);
(I think this is inside an ENTER_FRAME event?)
EDIT:
Some error countermeasures:
//Don't let health decrease below 0
if(health < 0) health = 0;
//And don't above 100
else if(health > 100) health = 100;
gotoAndStop(health + 1);
Use int instead of Number when you don't use decimal numbers and uint when you don't use negative integers (this bugs when the number can drop under 0, so for your health we take int):
health:int = 0;
I have been developing a very simple text game using Objective C and Xcode. It is almost done but I am having a problem, the scanf method stops the loop and asks for user input while I need the computer to be running the rest of the loop, the solution I came up with was running two while loops at the same time, one being the logic loop and another being a loop for user input.
I have been doing my research and it looks like using threads are the way to go, I just have not found a tutorial that will break it down for a n00b in Objective C (I am decent in java, I just have never worked with threads). If anybody could explain them or link me to a very broken down tutorial that would be great. Or if anybody has another idea I am open to anything else.
Necessary Code (The scanf I am having a problem with has asterisks on the line):
while(running != 0)
{
if(gameState == 1)
{
if(timeToGenerateNum == true)
{
while(randNumber < 10000000)
{
randNumber = arc4random() % 100000000;
}
NSLog(#"%i", randNumber);
timeToGenerateNum = false;
}
else
{
while(time <= 2500)
{
NSLog(#"Testing");
time++;
******************scanf("%i", &userNum);************************
if(userNum == randNumber)
{
score += time;
time = 0;
timeToGenerateNum = true;
}
}
NSLog(#"Game Over! Your score was %i!", score);
running = 0;
}
}
else if(gameState == 2)
{
NSLog(#"To play, simply type in the number that appears on the screen.");
NSLog(#"But be careful, you only have a short amount of time before GAME OVER!");
NSLog(#"The quicker you type in the number the more score you get!");
NSLog(#"Are you ready to start, if so type '1' and press enter!");
scanf("%i", &gameState);
}
}
You're going to have to learn a bit about BSD (Unix, Linux) input/output to pull this off: replace your call to scanf with a non-blocking function you write to acquire input from the user's keyboard.
This function should immediately return whatever the user typed, or immediately return with a zero character count if she didn't type anything.
Read up on the select(2) system call, and keep in mind that keyboard input (standard input) is the first file descriptor, file descriptor zero.