Drawstring refuses to stay on screen (XNA) - xna

been fighting with this problem for a good 3 hours now, and i figured it was finally time to ask some professionals.
My problem is that i want to make a scrollbar, and I've figured out that i want to make it by using two integers and then give every item in the list an ID, and then say that all the items that has an ID thats in between the two integers are going to be shown, and then afterwards make 2 buttons that will + or - the integers so you can "scroll" though the items.
So to realize this i decided to make dummy code, to see how i could work it out.
And for most part its working, however i have the problem now, that it seems that my draw function is refreshing the screen constantly (Even though I've put in a bool to make sure it woulden), and by doing that it keeps erasing the numbers I'm listing on the screen.
Heres the code:
List<int> test = new List<int>() {1,2,3,4,5,6,7 };
int low = 0;
int high = 3;
int count;
bool isDone = false;
public override void Draw(GameTime gameTime)
{
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null);
if (!isDone)
{
int posX = 20;
foreach (int nr in test)
{
if (count == high)
{
isDone = true;
break;
}
else
{
count++;
}
if (count >= low && count <= high)
{
posX += 20;
spriteBatch.DrawString(gameFont, nr.ToString(), new Vector2(posX, 20), Color.White);
}
}
}
spriteBatch.End();
}
Hopefully some of you clever folks can eye the mistake I've been missing.
Thanks in advance
~Etarnalazure.

You never reset your counter. Therefore, the numbers will be only visible in the first frame. Add
count = 0;
before the for-loop.
Furthermore, you might want to revise your structure. If you use a List<>, then every item already has its index. And you don't have to iterate over each and every item, if you use a for loop:
for(int i = low; i <= high; ++i)
{
var currentItem = list[i];
}

Related

Actionscript. Tween all the textfield with the text inside it

In my actionscript 3 i have a textfield, which i fill with the messages (get them from the webservice). Not all the messages are visible, so every (for Example) 5s i'm moving them vertically to the top.
To do that, i'm using the Tween effect, but the thing is, that it moves only the visible text and not the rest text together (the invisible one).
When scrolling - i can see the rest text.
Image to show the situation (Sorry for my skills):
Here are some code: Function to fill messages object. Plus count how many lines every message will take to display ( so i could easilly use the tween effect (From - to))
private function getNewMsg(e:ResultEvent):void
{
size = e.result.toString().split(" ").length - 1;
for (var i=0; i<size; i++)
{
smsList.push(new smsItem(e.result[i].Id, e.result[i].text));
}
summ = 0;
for (var d=0; d<size; d++)
{
textfield.appendText(smsList[d].Text.toUpperCase()+'\n');
if (d >= 1)
{
smsList[d].Lines = textfield.numLines - summ;
summ += smsList[d].Lines;
}
else
{
smsList[d].Lines = textfield.numLines-1;
summ += smsList[d].Lines + 1;
}
}
twEnd = smsList[1].Lines * (-30.5);
}
And on timer i'm starting the Tween:
function timerHandler(e:TimerEvent):void
{
myTweenX = new Tween(textfield, "y", None.easeIn, twStart, twEnd, 4, true)
myTweenX.addEventListener(TweenEvent.MOTION_FINISH, tweenCompleted);
}
function tweenCompleted(e:TweenEvent):void
{
twInd++;
twStart = twEnd;
twEnd += smsList[twInd].Lines * (-30.5);
}
Found the problem. Because of my fixed textfield height, text wasn't. After made the textfields height auto size, evrything got fixed.

Best solution for quickly loading a level select screen with 100+ buttons

I have a level select screen similar to candy crush's (a path of levels) where I plan to have more than 100 levels. When I load this many levels in one go, the time to create and load all of these levels is ~0.17 seconds. Now this is clearly much too long to wait after a user presses a button to go to the level. The game appears to freeze for a bit, then it finally goes.
Now I've been looking at a few different solutions to this. The one solution which I could revert to as a last resort is creating some sort of transition that temporarily shows a loading screen, then goes to the level select screen. It would be nice to bypass this loading all together though.
Currently my level select screen is a normal CCNode class with a scrollview on it. This means it is not a singleton, and every single time I go to it, a new instance loads. The nice thing about this is that I can constantly update whether or not someone has beaten a level, and change the color and ability to play the next level (is it possible to make this kind of update in a singleton class?). A singleton seems like the best approach to me (then I would just load in while the game loads at the beginning), but I'm not sure if the answer to my above question is yes. If someone has experience with this, please let me know!
I'm not really sure what else I could try to do. The only other good option seems to be somehow speeding up my code, but I'm not sure how I could do that (posted below). The last resort would be creating an instance of this class while my game loads, then just hide all user interaction on it whenever I don't want it to be showing. Idk though, that sounds a little sketch. Thanks for the advice, and here is my code creating the buttons.
-(void)didLoadFromCCB{
buttonArray = [NSMutableArray array];
CFTimeInterval startTime = CACurrentMediaTime();
CCSpriteFrame *redTile = [CCSpriteFrame frameWithImageNamed:#"Sprites/glossyTile.png"];
for (int l = 0; l < NUMBER_OF_WORLDS; l++) { //NUMBER_OF_WORLDS = 10
for (int j = 0; j < 4; j++) {
for (int k = 0; k < 5; k++) {
NSString *tempTitle = [NSString stringWithFormat:#"%i",(k+1)+(l*5)];
tempButton = [CCButton buttonWithTitle:tempTitle
spriteFrame:redTile
highlightedSpriteFrame:redTile
disabledSpriteFrame:nil];
tempButton.block = ^(id sender) {
CCNode *transitionScene = [CCBReader load:#"TransitionScene"];
[self addChild:transitionScene];
int row = k+1;
int column = j+1;
int buttonIndex = (row + (column-1)*5) + l*20;
for (int m = 1; m < buttonIndex; m++) {
[[LevelManager sharedInstance] nextLevel];
}
levelNumber = i;
[self performSelector:#selector(changeScenes) withObject:nil afterDelay:8.0/30.0
];
};
tempButton.position = ccp(someConstant*j, someConstant2*k + someConstant3*l);
[self addChild:tempButton];
i++;
}
}
}
CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
CCLOG(#"time interval media %f", elapsedTime); //logs about 0.17 seconds
}

objective-c: proper way to generate a lot of instances of a certain class without creating a memory leak?

I'm making a simple SpriteKit game. It has one randomly generated world made up of lines. These lines are represented by the NHRLineNode class. I generate these lines all at once in the beginning of the level with two for loops, one for each side of the screen. This works fine. In addition to the main gameplay scene of the game, there is a "game over" screen that displays between plays and shows your score etc and a main menu scene. The problem comes when I play the game, die, see the game over screen, and play again. Looking at the memory usage in Xcode, it seems like the memory usage goes up when I first start the game from the menu scene, stays steady throughout the gameplay, and then jumps 6-10 MB when I die. This memory is never regained and the app uses more and more memory every time I play. I think this is because my for loops that generate the platforms are just creating a new instance of the NHRLineNode class, positioning it correctly, and then doing it again. Is this what is causing my memory issues? Or is it more likely something on the game over scene?
Relevant snippets:
The for loops that generate the platforms:
int previousXVal1 = -10;
int previousYVal1 = 425;
int newXPosition = 0;
//How many do you want?
int numToGen = 100;
for(int i = 1; i<=numToGen; i++) {
NHRLineNode *lineGen = [NHRLineNode initAtPosition:CGPointMake(previousXVal1 + arc4random_uniform(85), previousYVal1 - 75)];
[worldNode addChild:lineGen];
if(lineGen.position.x > 390) {
newXPosition = lineGen.position.x - 100; //That should bring it onscreen!
lineGen.position = CGPointMake(newXPosition, lineGen.position.y); //Make the new position
} else if (lineGen.position.x < 100) {
newXPosition = lineGen.position.x + 100; //That will bring it onscreen!!
lineGen.position = CGPointMake(newXPosition, lineGen.position.y);
}
previousXVal1 = lineGen.position.x;
previousYVal1 = lineGen.position.y;
}
//This creates the lines on the right side (performing the inverse calculation on the x pos
//int numToGen = 10;
int previousXVal2 = 350;
int previousYVal2 = 525;
for(int i = 1; i<=numToGen; i++) {
NHRLineNode *lineGen = [NHRLineNode initAtPosition:CGPointMake(previousXVal2 - arc4random_uniform(85), previousYVal2 - 75)];
[worldNode addChild:lineGen];
if(lineGen.position.x > 390) { //It is partially off-screeb=n
newXPosition = lineGen.position.x - 100; //That should bring it onscreen!
lineGen.position = CGPointMake(newXPosition, lineGen.position.y); //Make the new position
} else if (lineGen.position.x < 100) { //It is partially off-screen
newXPosition = lineGen.position.x + 100; //That will bring it onscreen!!
lineGen.position = CGPointMake(newXPosition, lineGen.position.y);
}
previousXVal2 = lineGen.position.x;
previousYVal2 = lineGen.position.y;
}
The initAtPosition method of NHRLineNode:
+(id)initAtPosition:(CGPoint)point {
//This is all the properties of one of the lines in the level
SKSpriteNode *theLine = [SKSpriteNode spriteNodeWithImageNamed:#"newLine"];
//The physics body is slightly smaller than the image itself -- why idk
theLine.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(75,5)];
//It is not affected by gravity
theLine.physicsBody.dynamic = NO;
//Its position is the point given us when the function was called
theLine.position = point;
//Return it for further positioning by the generator
return theLine;
}
Entire implementation of GameOverScene: http://pastebin.com/wUpguueb
Thanks for your help.
Even though you have ARC on your side, sometimes you need to give it "incentive" to free objects, especially when creating many in a loop. Really, this simply has to do with providing scope, so ARC understands that it may release allocated instances.
Try wrapping the bodies of your for loops (i.e. not around the entire for loops), with #autoreleasepool { …} - i.e., as if that #autoreleasepool block is the only statement for the for loop.
Let is know if it helps! I commonly have to do this when iteratively importing data to Core Data.

How to speed up band selection tool in a Dart WebGL application

The task at hand is to add a band selection tool to a Dart WebGL application.
The tool will be used to draw a rectangle over multiple objects by dragging the mouse.
Thus multiple objects can be selected/picked in a single user action.
I'm currently using gl.readPixels() to read colors from an off-screen renderbuffer.
Problem is, when a large area is band-selected, gl.readPixels() issues millions of pixels.
Scanning such a big amount of colors wastes precious seconds just to locate few objects.
Please anyone point possibly faster methods for band-selecting multiple objects with Dart+WebGL.
For reference, I show below the current main portion of the band selection tool.
Uint8List _color = new Uint8List(4);
void bandSelection(int x, y, width, height, PickerShader picker, RenderingContext gl, bool shift) {
if (picker == null) {
err("bandSelection: picker not available");
return;
}
int size = 4 * width * height;
if (size > _color.length) {
_color = new Uint8List(size);
}
gl.bindFramebuffer(RenderingContext.FRAMEBUFFER, picker.framebuffer);
gl.readPixels(x, y, width, height, RenderingContext.RGBA, RenderingContext.UNSIGNED_BYTE, _color);
if (!shift) {
// shift is released
_selection.clear();
}
for (int i = 0; i < size; i += 4) {
if (_selection.length >= picker.numberOfInstances) {
// selected all available objects, no need to keep searching
break;
}
PickerInstance pi = picker.findInstanceByColor(_color[i], _color[i+1], _color[i+2]);
if (pi == null) {
continue;
}
_selection.add(pi);
}
debug("bandSelection: $_selection");
}
// findInstanceByColor is method from PickerShader
PickerInstance findInstanceByColor(int r, g, b) {
return colorHit(_instanceList, r, g, b);
}
PickerInstance colorHit(Iterable<Instance> list, int r,g,b) {
bool match(Instance i) {
Float32List f = i.pickColor;
return (255.0*f[0] - r.toDouble()).abs() < 1.0 &&
(255.0*f[1] - g.toDouble()).abs() < 1.0 &&
(255.0*f[2] - b.toDouble()).abs() < 1.0;
}
Instance pi;
try {
pi = list.firstWhere(match);
} catch (e) {
return null;
}
return pi as PickerInstance;
}
Right now I can see small solutions that might speed up your algorithm to limit as much as possible iterating over all of your elements,
The first thing you can do is have a default colour. When you see that colour, you know you don't need to iterate all over your array of elements.
It will accelerate large poorly populated areas.
It's very easy to implement, just adding a if.
For more dense areas you can implement some kind of colour caching. That means you store an array of colour you encountered. When you check a pixel, you first check the cache and then go over the entire list of elements, and if you find the element, add it to the cache.
It should accelerate cases with few big elements but will be bad if you have lots of small elements, which is very unlikely if you have picking...
You can accelerate your cache buy sorting your cached elements by last hit or/and by number of hits, it's very likely to find the same element in a continuous raw of pixels.
It's more work but stays relatively easy and short to implement.
Last optimisation would be to implement a space partitioning algorithm to filter the elements you want to check.
That would be more work but will pay better of on the long run.
edit :
I'm not a dart guy but this is how it would look like to implement in a basic way the first two optimisations:
var cache = new Map<UInt32, PickerInstance>();
for (int i = 0; i < size; i += 4) {
UInt32 colour = _color[i] << 24 | _color[i+1] << 16 | _color[i+2] << 8 | 0; // I guess we can just skip transparency.
if (_selection.length >= picker.numberOfInstances) {
// selected all available objects, no need to keep searching
break;
}
// black is a good default colour.
if(colour == 0) {
// if the pixel is black we didn't hit any element :(
continue;
}
// check the cache
if(cache[colour] != null) {
_selection.add(cache[colour]);
continue;
}
// valid colour and cache miss, we can't avoid iterating the list.
PickerInstance pi = picker.findInstanceByColor(_color[i], _color[i+1], _color[i+2]);
if (pi == null) {
continue;
}
_selection.add(pi);
// update cache
cache[colour] = pi;
}

randomness from spritemap in spritebatch

Im sure this is easily fixed, and I do have searched both high and low, traversed the net both east, west, north and south but to no prevail...
My problem is this. Im in the middle of trying to make a bejeweled clone, just to get me started in xna. However im stuck on the random plotting of gems/icons/pictures.
This is what i have.
First a generated list of positions, a random and a rectangle:
List<Vector2> platser = new List<Vector2>();
Random slump = new Random();
Rectangle bildsourcen;
protected override void Initialize()
{
for (int j = 0; j < 5; j++)
{
for (int i = 0; i < 5; i++)
{
platser.Add(new Vector2((i*100),(j*100)));
}
}
base.Initialize();
}
Pretty straight-forward.
I also have loaded a texture, with 5 icons/gems/pictures -> 5*100px = width of 500px.
allImage = Content.Load<Texture2D>("icons/all");
Then comes the "error".
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
int x = slump.Next(2);
bildsourcen = new Rectangle((x * 100), 0, 100, 100);
for (int i = 0; i < platser.Count; i++)
{
spriteBatch.Draw(allImage, new Rectangle((int)platser[i].X, (int)platser[i].Y, 100, 100), bildsourcen, Color.White);
}
So, there is my code. And this is what happens:
I want it to randomly pick a part of my image and plot it at the given coords taken from the vector2-list. However, it puts the same image at all coords and keeps randomly replacing them, not with random images but with the same. So the whole board keeps flickering the same icons. Ie, instead of generating 15231 and keeping it frozen, it one second puts 11111 and the next second it puts 33333.
Does anybody understand what im trying to describe ? I'm almost at the point of pulling my own hair out. The cat's hair has already been pulled...
Thx in advance
The Draw function is called once each frame. This line:
int x = slump.Next(2);
Is generating a random number (either a 0 or a 1 in this case) each frame, hence the flicker.
The line after that selects a sprite from your sprite atlas based on that number (specifically it specifies the rectangle containing that sprite). And in the loop that follows you're drawing multiple copies of that sprite (always the same image).
You should be doing all of your game logic in your Update function. That function will give you a time and you will probably want to implement a method of waiting for a certain amount of time to pass before you generate a random block (so keep accumulating the time that passes between each Update, until it reaches some threshold). The exact mechanics of when you want to generate your random block is up to you.
Of course, that is not to mention that there are other flaws in the structure of your code. Bejewelled is played on a fixed-sized board with different coloured blocks (each block you could represent with a number from 1 to X). The location of the blocks should be be implicit in your data structure (so you don't need to generate your platser list).
So your Game class should have something like:
const int BoardWidth = 10;
const int BoardHeight = 10;
int[,] board = new int[BoardWidth, BoardHeight];
Then in your Initialize function you should fill board and perhaps use 0 as an empty space and 1 to X to represent your colours, like so:
for(int x = 0; x < BoardWidth; x++) for(int y = 0; y < BoardHeight; y++)
{
board[x,y] = slump.Next(1, 6); // gives 5 different sprites
}
Then in Update wait for user input or a time-out before modifying the board (depending on your gameplay).
Then in your Draw function do something like this:
for(int x = 0; x < BoardWidth; x++) for(int y = 0; y < BoardHeight; y++)
{
if(board[x,y] == 0) continue; // don't render an empty space
Vector2 position = new Vector2(100*x, 100*y);
Rectangle bildsourcen = new Rectangle(100*(board[x,y]-1), 0, 100, 100);
sb.Draw(allImage, position, bildsourcen, Color.White);
}

Resources