Problems with my setInterval and if statement - if-statement

my first post here so bear with me :)
Im rediscovering my programing intrest with the "new" canvas elements and javascript and i tought i make a game for fun, pretty new to javascript tough.
The game is a hunting game and the problem i have is that when the animal comes into hearing range (a pixel representing the hunter and two circles around him represents his hearingrange and visionrange) he should say "i hear something" and in vision range he should shoot.
That all works fine but he spams the text and shooting every time the gameloop repeats and the animal is in range.
My tought was to use setInterval but i cant get it to work as i want :(
Here is my code:
var Interval = setInterval(function() {
hunterTimer()
},1000);
if (hunter.x >= moose.x-hunter.d1/2 &&
hunter.x <= moose.x+hunter.d2+hunter.d1/2 &&
moose.y >= moose.y-hunter.d1/2 &&
hunter.y <= moose.y+hunter.d2+hunter.d1/2) {
function hunterTimer() {
ctxtext.fillText("I hear something!",50,textbreak),
textbreak += 10;
}
hunterTimer();
}
Any help would be nice, sorry for the long post :D

I think the problem lies in the code structure. Can you try something like this (untested code):
var hunterTimer = function () {
if (hunter.x >= moose.x-hunter.d1/2 &&
hunter.x <= moose.x+hunter.d2+hunter.d1/2 &&
moose.y >= moose.y-hunter.d1/2 &&
hunter.y <= moose.y+hunter.d2+hunter.d1/2) {
ctxtext.fillText("I hear something!",50,textbreak),
textbreak += 10;
}
}
var interval = setInterval(hunterTimer, 1000);

Related

How to stop more than one being removed from an integer?

I know the title may seem fairly confusing, was just unsure on how to ask this...
So, I'm working on a basic sample game (not going to be a complete game or anything), where you can move around and are chased by an enemy character that attacks you. The problem is that when the attack function is called, instead of only removing one heart/hitpoint, they continue to be 'spam removed'. Here's what I'm working with...
void Enemy::attackPlayer()
{
if (distance < 50)
{
Player::health--;
return;
}
}
Pretty simple, right? Well the problem is that I need some way of I guess 'sleeping' the single function so that instead of continuing to remove health, it stops after one, then after let's say, 3 seconds, allows another attack to occur.
I think you can create two global time variables that are passed to your attack function. startTime is initiated once you call your attack function (outside). endTime is initiated right after removing one health from player (inside your function). Then you simply add a if statement before the distance if statement to check the delta time between these two and if they are more than 3 seconds then do the rest to remove another health.
You could probably have the Enemy class contain a method like:
bool canAttack(){
if(attackTimer >= 3000){
attackTimer = 0;
return true;
}
return false;
}
Then you could modify your damage condition to be something like:
if (distance < 50 && canAttack())
Of course, you would have to add a timer to the Enemy class and have it start and stop based on proximity to the player.
I'm sure there is a better way to handle this--also, this depends a bit on the implementation of the rest of your code. If you are using something like SFML, there is a built-in event system that would make this a bit easier to handle. Hopefully this helps a bit!
After taking some of the answers you guys gave me into consideration and messing around with some things by myself, I've came up with a pretty simple solution:
int Enemy::attackTime = 0;
And then...
void Enemy::attackPlayer()
{
if (distance > 60)
return;
if (time(0) > attackTime)
{
attackTime = time(0) + 3;
Player::health--;
}
}
I guess, player won't get another attacked from any enemy for 3 seconds. However, enemy can attack to another player if exist. Thus, this timer variable is keep into Player class. If I am correct, I think this code will work.
class Player
{
private:
uint32_t last_attack_timer;
...
public:
void set_last_attack_timer(uint32_t timer){this->last_attack_timer = timer;};
uint32_t get_last_attack_timer(void){return last_attack_timer;};
...
}
void Enemy::attackPlayer()
{
uint32_t timer = time(0);
if (distance < 50 && timer-Player::get_last_attack_timer>3000)
{
Player::health--;
Player::set_last_attack_timer(timer(0));
return;
}
}

VS2015 vector iterator not dereferencable

I have a little problem, I have to build a 2D game based on SDL.
I just keep getting this errror when I try to delete 2 objects that are colliding in "Scene".
std::vector<WaspObject*>::iterator itw;
std::vector<ProjectileObject*>::iterator itp;
for (itp = _projectiles.begin(); itp != _projectiles.end();)
{
for (itw = _wasps.begin(); itw != _wasps.end();)
{
if ((*itw)->Get_PositionY() + 37 >= (*itp)->Get_PositionY() + 0 && (*itp)->Get_PositionX()+0 >= (*itw)->Get_PositionX()+0 && (*itp)->Get_PositionX()+0 <= (*itw)->Get_PositionX()+49)
{
itw = _wasps.erase(itw);
itp = _projectiles.erase(itp);
}
else
{
itw++;
itp++;
}
}
}
_wasps and _projectiles are std vectors in this scene.
Can someone help me find the problem? Thanks in advance!
If you don't get any hits and increment itp in the inner loop, it might well run past _projectiles.end().
For example if there are more wasps than projectiles. Or if you are on the last projectile, where you will reach _projectiles.end() after a single itp++.
So you might want to test both end conditions at each turn of the inner loop.

How would I randomly create typos in a std::string?

Ok so I'm working on a chatbot and I have a private std::string called m_sResponse. This string is outputted using
void print_response() const {
if(m_sResponse.length() > 0) {
std::cout << m_sResponse << std::endl;
}
}
I want to create a function that will misspell m_sRensponse let's say 5% of the time so the chatbot seams more human like. How would I accomplish this?
To make it seem more realistic, I'd make a map<char,vector<char>> of appropriate 'substitution' keys based off of keyboard layouts (e.g. QWERTY). Basically, it seems more real if your typo is "responsw" than "responsl" since "w" and "e" are next to each other. You'll also want to randomly delete or insert letters too. I'd assign a frequency to "errors" and then a frequency of each kind of error.
Now that you've got this and the other answers handling the randomness aspect (if(rand(100)<5)), you should be able to replicate the desired typo handler.
Pseudocode:
if rand(100) < 5
randomIndex = rand(string.length())
randomChar = rand(26)
string[randomIndex] = randomChar
You can use a random seed and use %5 for like 20% of the time ish.
if((rand() % 5) == 0) {
int t = rand() & m_sResponse.length();
char a = m_sResponse[t];
m_sResponse[t] = m_sResponse[t+1];
m_sResponse[t+1] = a;
}

Stuck in Infinite Recursion

I have this function to solve a maze in C++, but when I run the program I get a Bad Access Error in the recursion. I think in may be an infinite loop. I have no idea where and what is going wrong.
bool Solve_Maze(int coorx,int coory) {
if((Map[coorx][coory]==Start)||(Map[coorx][coory]==path)) {
Map[coorx][coory]=wall;
Solve_Maze(coorx+1,coory);
Solve_Maze(coorx-1,coory);
Solve_Maze(coorx,coory+1);
Solve_Maze(coorx,coory-1);
}else if(Map[coorx][coory]==End) {
cout<<"You Solved the Maze!"<<endl;
delete Map;
return(true);
}
}
1) You are not returning any value in if statement
2) Map[coorx][coory] always assigned to wall in all function call..Does wall refers to a global state?
I changed the function to return void since the value wasn't properly being returned up the stack. In this case you will just use the global found variable to check if the end was found. (this will require you to set 'found = false' every time before you run the function).
bool found = false;
You also want to do some input validation
if( coorx > maxX || coorx < 0 || coory > maxY || coory < 0) return;
You will need to replace maxX and maxY with 1 more than your maximum values for coorx and coory. That will ensure you don't get a bad access error.
bool found = false; // this will be global scope or pass it by reference
Solve_Maze(x,y);
// if(found) - found will be true if you found the end
void Solve_Maze(int coorx,int coory) {
if( coorx > maxX || coorx < 0 || coory > maxY || coory < 0) return;
else if(((Map[coorx][coory]==Start)||(Map[coorx][coory]==path))) {
Map[coorx][coory]=wall;
Solve_Maze(coorx+1,coory);
Solve_Maze(coorx-1,coory);
Solve_Maze(coorx,coory+1);
Solve_Maze(coorx,coory-1);
}else if(Map[coorx][coory]==End) {
cout<<"You Solved the Maze!"<<endl;
delete Map;
found = true;
}
}
Run it in a debugger (gdb or dbx). Compile with the -g flag so your program can be debugged. If you don't know how to use a debugger, google "dbx cheatsheet." You can isolate where it's stuck in the loop (if your guess is right) and step your way through. The total time it will take you to become proficient enough in a debugger to do this is, and to actually do it, is less than the amount of time you have spent thinking about it already.
No sarcasm is intended - people really do often overestimate the work in learning a debugger, so I want to really assert the point that it's worth it even for a simple problem, and tremendously pays off for big problems.

How can I get the enemies to move?

Hello I am trying to get enemies to move left and right as if they are sliding backwards and forwards I know this can be done with the following code:
slide += slide_incr;
if(abs(slide)>30) slide_incr = -slide_incr;
However this is of no use to me as I need to set a boolean so I can cycle through the frames for when the enemy is going right or going left.
Ive tried the follow code with no luck:
if(abs(eSlide)<=0)
{
eSlide += eSlide_incr;
}
if(abs(eSlide)>30)
{
eSlide_incr = -eSlide_incr;
}
Any ideas on how I can implement it?
Thanks
You want to hold a hysteresis state for if you're sliding forward or backward. You are also mixing up how to use the abs() function when bounds checking. Try something along the lines of:
eSlide += eSlide_incr;
if (abs(eSlide) >= 30) {
eSlide_incr = -eSlide_incr;
}
the first thing that stands out for me is that the contents of the block:
if (abs(eSlid) <= 0) {
eSlide += eSlide_incr;
}
will never ever run (the absolute value will always be greater than or equal to 0)
as for your boolean facing, that can be achieved with:
bool isSlidingRight = eSlide_incr > 0;
(note: this would still use the left animation set for values of 0)