After profiling my app, I appear to have a memory leak somewhere in this method:
- (void) didEvaluateActions {
for (int x = 0; x < self.children.count; x++) {
if ([self.children[x] isKindOfClass:[BallNode class]]) {
BallNode * ball = (BallNode *) self.children[x];
if (abs(ball.physicsBody.velocity.dx) < BALL_MIN_VEL_X) {
ball.physicsBody.velocity = CGVectorMake((ball.physicsBody.velocity.dx < 0 ? -1 : 1) * BALL_MIN_VEL_X, ball.physicsBody.velocity.dy);
}
if (abs(ball.physicsBody.velocity.dx) > BALL_MAX_VEL_X) {
ball.physicsBody.velocity = CGVectorMake((ball.physicsBody.velocity.dx < 0 ? -1 : 1) * BALL_MAX_VEL_X, ball.physicsBody.velocity.dy);
}
if (abs(ball.physicsBody.velocity.dy) < BALL_MIN_VEL_Y) {
ball.physicsBody.velocity = CGVectorMake(ball.physicsBody.velocity.dx, (ball.physicsBody.velocity.dy < 0 ? -1 : 1) * BALL_MIN_VEL_Y);
}
if (abs(ball.physicsBody.velocity.dy) > BALL_MAX_VEL_Y) {
ball.physicsBody.velocity = CGVectorMake(ball.physicsBody.velocity.dx, (ball.physicsBody.velocity.dy < 0 ? -1 : 1) * BALL_MAX_VEL_Y);
}
}
}
}
I'm not seeing where this method could be causing a memory leak. BallNode is not created here, so why is instruments pointing back to this location? How is this method causing a leak?
-Thank in advance
I it doesn't appear that you are doing anything wrong, but if you are pointing the the correct spot in code then I think it has to do with self.children.count
Try
NSUInteger count = self.children.count;
for (NSInteger x = 0; x < count; x++)
{
if ([self.children[x] isKindOfClass:[BallNode class]]) {
BallNode * ball = (BallNode *) self.children[x];
if (abs(ball.physicsBody.velocity.dx) < BALL_MIN_VEL_X) {
ball.physicsBody.velocity = CGVectorMake((ball.physicsBody.velocity.dx < 0 ? -1 : 1) * BALL_MIN_VEL_X, ball.physicsBody.velocity.dy);
}
if (abs(ball.physicsBody.velocity.dx) > BALL_MAX_VEL_X) {
ball.physicsBody.velocity = CGVectorMake((ball.physicsBody.velocity.dx < 0 ? -1 : 1) * BALL_MAX_VEL_X, ball.physicsBody.velocity.dy);
}
if (abs(ball.physicsBody.velocity.dy) < BALL_MIN_VEL_Y) {
ball.physicsBody.velocity = CGVectorMake(ball.physicsBody.velocity.dx, (ball.physicsBody.velocity.dy < 0 ? -1 : 1) * BALL_MIN_VEL_Y);
}
if (abs(ball.physicsBody.velocity.dy) > BALL_MAX_VEL_Y) {
ball.physicsBody.velocity = CGVectorMake(ball.physicsBody.velocity.dx, (ball.physicsBody.velocity.dy < 0 ? -1 : 1) * BALL_MAX_VEL_Y);
}
}
}
The way you have it currently it is trying to evaluate self.children.count every iteration through the loop. This shouldn't cause a leak, but there could be something under the hood preventing it from being released correctly when evaluating it repeatedly.
Also you may want to look at enumerateChildNodesWithName: as a quicker alternative than looking at every child and seeing if it is a BallNode.
Hopefully that is the issue and is easily fixed.
You keep creating more and more instances of your BallNode class. Try adding ball = nil; after your last if statement but honestly I do not know if that will help you.
Either your code logic is wrong or there is other stuff going on which you did not post. Usually it would make sense for you to have an ivar of your ball which you would apply the posted code to.
Related
Hey guys I'm new to Game Maker Studio and new to the language. I'm making a game and have been working on the dialogue system.
This chunk of code was designed for characters respond to a set of choices, the dialogue starts by printing out the first element of the line_array, which it does, then give the player the choice of two responses from the response_array, which it insteads prints out the second element of the line_array and I don't understand why.
Does an argument only hold one element of an array? I'm initializing two arrays in an object oCivilian2 and pushing them through code DialogueCode which is linked to another object oRespond that supposed to allow me to sift through dialogue in game. Anything helps thanks
It's initialized here in create of oCivilian2
line_array = [3];
line_array[0] = "Ethan it's good to see you! \n I thought after the incident well.... \n well I thought we had lost you";
line_array[1] = "I've said too much";
line_array[2] = "You hit your head trying to saver her\n It was horrible";
response_array = [2];
response_array[0] = "What happened?";
response_array[1] = "I don't recall alot. How bad was it?";
counter = 0;
x1 = RESOLUTION_W / 2;
y1 = RESOLUTION_H -70;
x2 = RESOLUTION_W/2;
y2 = RESOLUTION_H;
_print = "";
responseSelected = 0;
Then the step which links it to DialogueCode when spacebar is pressed
keyActivate = keyboard_check_pressed(vk_space);
if (keyActivate)
{
var inst = collision_rectangle(oPlayer.x+3,oPlayer.y+3,oPlayer.x-3,oPlayer.y-3, oCivilian2, false, false);
if (inst != noone)
{
ScriptExecuteArray(DialogueCode, line_array);
ScriptExecuteArray(DialogueCode, response_array);
}
}
Then through to step in the object oRespond
lerpProgress += (1 - lerpProgress) / 50;
textProgress += global.textSpeed;
x1 = lerp(x1, x1Target,lerpProgress);
x2 = lerp(x2, x2Target,lerpProgress);
keyUp = (keyboard_check_pressed(vk_up)) || (keyboard_check_pressed(ord("W")))
keyDown = keyboard_check_pressed(vk_down) || keyboard_check_pressed(ord("S"));
responseSelected += (keyDown - keyUp);
var _max = 2;
var _min = 0;
if (responseSelected > _max) responseSelected = _min;
if (responseSelected < _min) responseSelected = _max;
for (var i = 0; i < 2; i++)
{
var _marker = string_pos(",", response);
if (string_pos(",",response))
{
responseScript[i] = string_copy(response,0,_marker);
string_delete(response,0,_marker);
var _marker = string_pos(",", response);
}
else
{
responseScript[i] = string_copy(response,0, string_length(response));
}
}
if (keyboard_check_pressed(vk_space))
{
counter++;
}
Then to print in oRespond
/// text
//response
NineSliceBoxStretched(sTextBox, x1,y1,x2,y2, 0);
draw_set_font(fText);
draw_set_halign(fa_center);
draw_set_valign(fa_top);
draw_set_color(c_black);
if (counter % 2 == 0)
{
var _i = 0;
var _print = string_copy(text,1,textProgress);
draw_text((x1+x2) / 2, y1 + 8, _print);
draw_set_color(c_white);
draw_text((x1+x2) / 2, y1 + 7, _print);
_i++;
}
else
{
if (array_length_1d(responseScript) > 0)
{
var _print = "";
for (var t = 0; t < array_length_1d(responseScript); t++)
{
_print += "\n";
if (t == responseSelected) _print += "--> "
_print += responseScript[t];
show_debug_message(responseScript[t]);
if (t == responseSelected) _print += " <-- "
}
draw_text((x1+x2) / 2, y1 + 8, _print);
draw_set_color(c_white);
draw_text((x1+x2) / 2, y1 + 7, _print);
}
}
Alright, i think to see many problems with your code.
First of all, since arrays in GM are dynamic declare them like
line_array[3]
is a bad practice (in my point of view)
I've never declared an array this way in GM so that could be the problem here.
Second, i don't really understand the logic of your code, always create objects, at least in the GM environment, that corresponds to "physical" entities, i would make an object for the Civilian but not for the "respond".
I've red your code a lot of times and since no one answered you in 3 months i can assume it's because no one can really understand your way of coding, and this way of coding will probably give you a lot of problems in future. The thing that you're trying to doing could be super-easy if done with a good hierarchy.
I would like to help u with this code, but i find it very chaotic.
If you've not resolved this problems, write a comment :)
I advice you to fully re-implement it even if resolved anyway.
I have a question on this code.
It's the code for finding delay.
in order to estimate the delay,
in my mind,I should find the largest value from the array mean_bit_counts[], but in the picture, they choose the smallest one. So could you solve my problem? Thanks!
// Find |candidate_delay|, |value_best_candidate| and |value_worst_candidate|
// of |mean_bit_counts|.
for (i = 0; i < self->history_size; i++) {
if (self->mean_bit_counts[i] < value_best_candidate) {
value_best_candidate = self->mean_bit_counts[I];
candidate_delay = I;
}
if (self->mean_bit_counts[i] > value_worst_candidate) {
value_worst_candidate = self->mean_bit_counts[I];
}
}
valley_depth = value_worst_candidate - value_best_candidate;
I have the following code:
- (NSArray *)checkNormalGameDuelAndMatch:(float)nrDuelQs andNrQPerDuel:(float)nrQPerDuel andNrMatchQ:(float)nrMatchQ andActivePlayer:(float)actPlayerNrQ andInactivePlayer:(float)inactivePlayerNrQ {
NSLog(#"checkNormalGameDuelAndMatch:");
// Check for Matches and Duels to prep for swaps and/or match endings
NSArray *theCheckArray = [[NSArray alloc]init];
NSLog(#"nrDuelQs: %.0f / nrQPerDuel: %.0f", nrDuelQs, nrQPerDuel);
// Check if Match still on
NSLog(#"actPlayerNrQ: %.0f / inactivePlayerNrQ: %.0f / nrMatchQ: %.0f", actPlayerNrQ, inactivePlayerNrQ, nrMatchQ);
if (actPlayerNrQ < nrMatchQ && inactivePlayerNrQ < nrMatchQ) {
// Match is still on
_isMatchStillOn = YES;
// Check if Duel is till on
if (nrDuelQs < nrQPerDuel) {
// Duel is still on
_isDuelStillOn = YES;
NSLog(#"_isDuelStillOn = YES;");
}
else {
_isDuelStillOn = NO;
NSLog(#"_isDuelStillOn = NO;");
}
}
else {
//==MATCH IS OVER==//
_isMatchStillOn = NO;
NSLog(#"MATCH OFF");
}
theCheckArray = #[[NSNumber numberWithBool:_isDuelStillOn], [NSNumber numberWithBool:_isMatchStillOn]];
return theCheckArray;
}
With the following NSLog output, during two loops:
checkNormalGameDuelAndMatch:
nrDuelQs: 4 / nrQPerDuel: 5
actPlayerNrQ: 4 / inactivePlayerNrQ: 0 / nrMatchQ: 5
_isDuelStillOn = YES;
checkNormalGameDuelAndMatch:
nrDuelQs: 5 / nrQPerDuel: 5
actPlayerNrQ: 5 / inactivePlayerNrQ: 0 / nrMatchQ: 5
MATCH OFF
I guess there is something wrong with the If-statement and "&&" as i am not expecting the "MATCH OFF" when it comes.
I guess i am blind as this should not be complicated.
This is very likely happening because the variables are of the type float: even through they both print as 5, one of them may be actually slightly smaller than the other (say, 4.9999999999999999). This could happen because of the way actPlayerNrQ is calculated: for example, if you add 0.1 fifty times, you would not get exactly a 5.
Here is a link to an example (it is in C, but that part of the language is shared with Objective C).
float n = 0;
int i = 0;
for (i = 0 ; i != 25 ; i++, n += 0.2);
printf("%f < 5.000000 : %s", n, n < 5.0 ? "yes":"no");
This prints
5.000000 < 5.000000 : yes
To fix this, you could compare with an epsilon, for example
#define EPSILON 1E-8
// 1E-8 stands for 1*10^-8, or 0.00000001
...
if ((actPlayerNrQ - nrMatchQ) < EPSILON && (inactivePlayerNrQ - nrMatchQ) < EPSILON)
...
While doing some work for my lab in university
I am creating this function where there is a for loop inside another one.
It is not important to know what the method is used for. I just can't figure out why the program doesn't enter the second for loop. This is the code:
public void worseFit(int[] array){
int tempPosition = -1;
int tempWeight = 101 ;
for (int x = 0; x < (array.length - 1); x++){
if (allCrates.getSize() < 1){
Crate crate = new Crate();
crate.addWeight(array[0]);
allCrates.add(crate);
} else{
for( int i = 1; i < (allCrates.getSize() - 1); i++ ){
Crate element = allCrates.getElement(i);
int weight = element.getTotalWeight();
if (weight < tempWeight){
tempWeight = weight;
tempPosition = i;
Crate crate = new Crate();
if (weight + tempWeight <= 100){
crate.addWeight(weight + tempWeight);
allCrates.setElement(i, crate);
} else {
crate.addWeight(weight);
allCrates.setElement(allCrates.getSize(), crate);
} // if
} // if
} // for
} // if
} // for
} // worseFit
Once the program enters the else part of the code it goes straight
away back to the beginning of the first for loop.
Would anyone know how to solve this problem?
There seems to be some discrepancies with the expected values of allCrates.getSize().
If allCrates.getSize() returns 2, it will go to the second for loop, but not run it, as i < allCrates.getSize() - 1 will result in false
You might want to use <= instead of <
Initialize the variable i in your second loop to 0 instead of 1. Because if your getSize() returns 1 the it will not enter the if part and after entering the else part the for loop condition will evaluate to false and hence your for loop will not be executed.
i'm making a simple iPhone game using cocos2d-iphone. I have an array of fiends, the "fiendSet" which has to navigate around a field full of obstacles. I spent the last three nights trying to get my A* pathfinding to work. I found the actual A* implementation here on stackoverflow and it works brilliantly. However, once i try to move my fiends around i run into trouble.
Each of my fiends has a CGPoint called motionTarget which contains the x and y values for where the fiend has to go. If only set the positions x and y to absolute values once a second, it works, like so:
-(void) updateFiendPositions:(ccTime)dt {
for (MSWFiend *currFiend in fiendSet) {
currFiend.position = ccp(currFiend.motionTarget.x,currFiend.motionTarget.y);
}
}
However, this doesn't look very nice, the fiends just "jump" 20px each second instead of animating nicely. I only implemented this as a placeholder method to verify the pathfinding. Now i want smooth animation. This is what i did:
-(void) updatePositions:(ccTime) dt {
for (MSWFiend *currFiend in fiendSet) {
if (currFiend.motionTarget.x != -1 && currFiend.motionTarget.y != -1) {
float x,y;
if ((int)floor(currFiend.position.x) < (int)floor(currFiend.motionTarget.x)) {
x = currFiend.position.x+(currFiend.speed*dt);
}
if ((int)floor(currFiend.position.x) > (int)floor(currFiend.motionTarget.x)) {
x = currFiend.position.x-(currFiend.speed*dt);
}
if (abs((int)floor(currFiend.position.x)-(int)floor(currFiend.motionTarget.x)) < 2) {
x = currFiend.motionTarget.x;
}
if ((int)floor(currFiend.position.y) < (int)floor(currFiend.motionTarget.y)) {
y = currFiend.position.y+(currFiend.speed*dt);
}
if ((int)floor(currFiend.position.y) > (int)floor(currFiend.motionTarget.y)) {
y = currFiend.position.y-(currFiend.speed*dt);
}
if (abs((int)floor(currFiend.position.y)-(int)floor(currFiend.motionTarget.y)) < 2) {
y = currFiend.motionTarget.y;
}
currFiend.position = ccp(x,y);
}
}
}
This works great for fiends moving in one direction. As soon as a fiend is supposed to go around a bend, trouble starts. Instead of for example first going up, then right, then down; my fiends will combine the up/right motion into one, they are "cutting corners". I only want my fiends to move either north/south OR east/west for each position update, not both. In other words, i don't want to animate changes to x and y simultaneously. I hope this explanation is clear enough..
I'm pretty sure i have a logic error somewhere.. i just havn't been able to figure it out for the last three sleepless nights after work.. Help!
You have to keep track of each node in the path to the target. That way you only animate the motion to the next node. Also you can use a CCMoveTo action instead on doing the animation yourself.
#Aleph thanks for your suggestion. I found that it was the code which determines when to assign a new motionTarget, that was faulty, not the code i posted to begin with. When you mentioned keeping track of each nodes position, i thought of my motionTarget determination code and found the error after 2-3 hours. I ended up doing it like this:
-(void) updatePositions:(ccTime) dt {
for (MSWFiend *currFiend in fiendSet) {
int fiendGX,fiendGY,targetGX,targetGY,dGX,dGY;
float x,y,snappedX,snappedY;
BOOL snappedIntoPosition = FALSE;
fiendGX = (int)round(100.0f*(currFiend.position.x/20));
fiendGY = (int)round(100.0f*(currFiend.position.y/20));
targetGX = (int)round(100.0f*(currFiend.motionTarget.x/20));
targetGY = (int)round(100.0f*(currFiend.motionTarget.y/20));
snappedX = currFiend.position.x;
snappedY = currFiend.position.y;
dGX = abs(fiendGX-targetGX);
dGY = abs(fiendGY-targetGY);
float snappingThreshold; //1 = snap when 0.1 from motionTarget.
snappingThreshold = currFiend.speed/10;
if (dGX < snappingThreshold && dGY < snappingThreshold) {
snappingThreshold = currFiend.motionTarget.x;
snappingThreshold = currFiend.motionTarget.y;
int newPathStep;
newPathStep = currFiend.pathStep + 1;
currFiend.pathStep = newPathStep;
}
int gX,gY;
gX = [[currFiend.path objectAtIndex:currFiend.pathStep] nodeX];
gY = (tileMap.mapSize.height-[[currFiend.path objectAtIndex:currFiend.pathStep] nodeY])-1;
currFiend.motionTarget = ccp(gX*20,gY*20); //Assign motion target to the next A* node. This is later used by the position updater.
if (currFiend.motionTarget.x != -1 && currFiend.motionTarget.y != -1) {
x = currFiend.motionTarget.x;
y = currFiend.motionTarget.y;
if ((int)floor(currFiend.position.x) < (int)floor(currFiend.motionTarget.x)) {
//Move right
x = snappedX+(currFiend.speed*dt);
if (x > currFiend.motionTarget.x) {
x = currFiend.motionTarget.x;
}
y = snappedY;
}
if ((int)floor(currFiend.position.x) > (int)floor(currFiend.motionTarget.x)) {
//Move left
x = snappedX-(currFiend.speed*dt);
if (x < currFiend.motionTarget.x) {
x = currFiend.motionTarget.x;
}
y = snappedY;
}
if ((int)floor(currFiend.position.y) < (int)floor(currFiend.motionTarget.y)) {
//Move up
y = snappedY+(currFiend.speed*dt);
if (y > currFiend.motionTarget.y) {
y = currFiend.motionTarget.y;
}
x = snappedX;
}
if ((int)floor(currFiend.position.y) > (int)floor(currFiend.motionTarget.y)) {
//Move down
y = snappedY-(currFiend.speed*dt);
if (y < currFiend.motionTarget.y) {
y = currFiend.motionTarget.y;
}
x = snappedX;
}
}
currFiend.position = ccp(x,y);
}
}