So I have started to mess around with XNA today and I am still learning C#. I am trying to produce a main menu for a game.
I have made a sprite font file and am producing the text I want. The code for this is:
spriteBatch.DrawString(font, ">://Start Game [1]", new Vector2(0, 0), Color.LimeGreen);
My question is that I have a method to make a typing effect from the "computer" (which I asked a question about a few days ago), but this is in C++. I have an idea how to convert it into C#, but even if I do convert the code correctly, how do I apply the method onto the text being created? Is their a more efficient way to print text in XNA?
The code for the typing effect in C++ is:
void typeOutput(string displayString){
for(int i = 0; i < displayString.length(); i++){
cout << displayString[i];
Sleep((rand() + 1)%typeSpeed);
}
}
There are various ways to do this which is discussed in this thread. One example from that thread is:
// our string will take 3 seconds to appear
private const float timerLength = 3f;
private float timer = 0f;
Then in your Draw method you add to the timer and use that to determine how much of the string to draw:
timer += (float)gameTime.ElapsedGameTime.TotalSeconds;
// if the timer is passed timerLength, we just draw the whole string
if (timer >= timerLength)
{
spriteBatch.DrawString(myFont, myString, stringPosition, stringColor);
}
// otherwise we want to just draw a substring
else
{
// figure out how many characters to show based on
// the ratio of the timer to the timerLength
int numCharsToShow = (int)(myString.Length * (timer / timerLength));
string strToDraw = myString.Substring(0, numCharsToShow);
// now just draw the substring instead
spriteBatch.DrawString(myFont, strToDraw, stringPosition, stringColor);
}
Related
I've made boids in unity but when trying to render a 1000 of them the performance is really bad, in my update function i use Physics.OverlapCircleAll to check all surroundiing boids. Is there any way to do this more optimized? Here is my update function:
void Update()
{
Collider2D[] hitColliders = Physics2D.OverlapCircleAll(Position, radius,layerMask.value);
List<Boid> boids = hitColliders.Select(o => o.GetComponent<Boid>()).ToList();
boids.Remove(this);
Flock(boids.ToArray());
}
Absolutely! Physics.OverlapCircleAll creates a lot of garbage every time it is called. What you're looking for is Physics.OverlapCircleNonAlloc, which will not create any garbage as it uses a buffer:
Collider2D[] hitsBuffer = new Collider2D[30]; //limit the amout of possible boid interations
void Update()
{
int numHits = Physics2D.OverlapCircleNonAlloc(Position, radius, hitsBuffer, layerMask.value);
Flock(hitsBuffer,numHits);
}
void Flock(Collider2D[] hitsBuffer, int numHits){
for(int i = 0; i < numHits; i++){
var boid = hitsBuffer[i].GetComponent<Boid>();
if(boid == this)
continue;
//flocking algorith here
}
}
Note how in the above code no additional arrays are created each frame, which is quite expensive. To check how much time is being spent where check out the Profiler:
Orange is 'Physics', working out the overlaps
Cyan is 'Scripts', calcuations in code, ie the flocking algorithm
Dark green is 'GarbageCollector', handling arrays created and destroyed each frame
PS If not already, ensure that the boids are using a CircleCollider2D, this is the easiest for Unity to calculate.
PPS You may want to double check that if(boid == this) actually gets called. I thought that Physics.Overlap... ignores this collider.
I'm trying to make a simple game where there's a zombie horde coming from the top of the screen to the bottom. I want that a new zombie appears every 5 seconds, and it does, but every time a new zombie appears the previous one stops moving and the collision doesn't work on that one. Can someone help me understand this behaviour and what's the best way to make it work the way its supposed to? :)
Here is my where I create the zombie:
private void CreateZombie()
{
zombieSprite = new CCSprite ("zombie");
zombieSprite.PositionX = CCRandom.GetRandomFloat (10, 600);
zombieSprite.PositionY = 1055;
AddChild (zombieSprite);
}
and here's the code inside my gamelogic method:
void GameLogic (float frameTImeInSeconds) {
zombieYVelocity += frameTImeInSeconds * -gravity;
zombieSprite.PositionY += zombieYVelocity * frameTImeInSeconds;
if (timer % 5 == 0) {
CreateZombie ();
zombieYVelocity = 0;
}
}
I attached a screenshot that shows whats happening
Every 5 seconds when a new one is added the previous one stops, and the collision detection is no longer working with the ones that are stoped.
Heyo, I'm trying to make my GUI fade when not in use. Specifically, for a Minecraft-style tool bar, I want it to pop in when a player uses the scroll wheel and fade away in a few seconds after they're done scrolling. The GUI is working perfectly, but I can't get this fading thing to work. I assume once I get the selection text working, the sprites will follow easily, so I'll just talk about the selection text for now. The inventoryText starts the game at full white.
protected void OnGUI()
{
if (isInvGUIDirty)
{
// Update selection text
controllerInterface.inventoryText.CrossFadeAlpha(255f, 0, false);
controllerInterface.inventoryText.CrossFadeAlpha(0.1f, 2, false);
^ This results (when I move the scrollwheel) in the inventory text going full-white, and two seconds later shifting to a light grey. There is no sleek transition, and it is still clearly visible. This repeats every time I move the scrollwheel.
controllerInterface.inventoryText.CrossFadeAlpha(255f, 0, false);
controllerInterface.inventoryText.CrossFadeAlpha(0f, 2, false);
^ This results (when I move the scrollwheel) in the inventory text going full-white, and two seconds later shifting to invisible. This repeats every time I move the scrollwheel. Apparently 0.1 alpha makes all the difference o_O
controllerInterface.inventoryText.color = Color.white;
controllerInterface.inventoryText.CrossFadeAlpha(0.1f, 2, false);
^ This results in the inventory text slowly fading to a light grey, but no change on scrollwheel.
Any ideas on why CrossFadeAlpha() isn't working as expected?
Sorry, wasn't getting email updates from here :/. So what I ended up doing that worked was to write my own coroutine at the most basic level, which seemed to work...for some reason. Honestly, not sure why the previous didn't work. This operates on a CanvasGroup instead of the individual items too.
private void FadeInventoryGroup(float alpha, float delay)
{
if (fader != null)
StopCoroutine(fader);
fader = StartCoroutine(EFadeOutInventory(alpha, delay));
}
private IEnumerator EFadeOutInventory(float alpha, float delay)
{
yield return new WaitForSeconds(delay);
float progress = 1f - Mathf.Abs(inventoryGroup.alpha - alpha);
float start = inventoryGroup.alpha;
while (progress < 1f)
{
progress += Time.deltaTime;
inventoryGroup.alpha = Mathf.Lerp(start, alpha, progress);
yield return 0;
}
}
I'm building my very first game with XNA and i'm trying to get my sprite to run.
Everything is working fine for the first sprite.
E.g : if I go right(D) my sprite is looking right , if I go left(A) my sprite is looking left and if I don't touch anything my sprite is the default one.
Now what I want to do is if the sprite goes Right, i want to alternatively change sprites (left leg, right leg, left leg etc..) xCurrent is the current sprite drawn xRunRight is the first running Sprite and xRunRight1 is the one that have to exchange with xRunRight while running right.
This is what I have now :
protected override void Update(GameTime gameTime)
{
float timer = 0f;
float interval = 50f;
bool frame1 = false ;
bool frame2 = false;
bool running = false;
KeyboardState FaKeyboard = Keyboard.GetState();
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if ((FaKeyboard.IsKeyUp(Keys.A)) || (FaKeyboard.IsKeyUp(Keys.D)))
{
xCurrent = xDefault;
}
if (FaKeyboard.IsKeyDown(Keys.D))
{
timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds;
if (timer > interval)
{
if (frame1)
{
xCurrent = xRunRight;
frame1 = false;
}
else
{
xCurrent = xRunRight1;
frame1 = true;
}
}
xPosition += xDeplacement;
}
Any ideas...? I've been stuck on this for a while..
Thanks in advance and let me know if you need any other part from the code.
You forgot to reset the timer, you could do this when you hit the timer interval condition. Also, 50ms seems a bit too small for an interval, maybe you could do like 400ms?
Other than that, looks good, it will do what you want.
Alternatively, you could look into making animated sprites for walking. What you do is make an image with the walking animation sprites one next to the other, of the same size. You draw only a portion of this image (one sprite) and move through them based on time.
Here is a quick code for what could be an animated texture:
class AnimatedTexture2D : Texture2D
{
int _numberOfImages;
int _currentImage = 0;
int _timeInterval;
int _spriteWidth;
public Rectangle DrawFromRectangle
{
get
{
return new Rectangle(_currentImage * _spriteWidth, 0, _spriteWidth, this.Height);
}
}
public AnimatedTexture2D(Texture2D entireImage, int spriteWidth, int numberOfImages, int timeInterval)
: base(entireImage.GraphicsDevice, entireImage.Width, entireImage.Height)
{
_numberOfImages = numberOfImages;
_timeInterval = timeInterval;
_spriteWidth = spriteWidth;
Color[] data = new Color[entireImage.Width * entireImage.Height];
entireImage.GetData<Color>(0, new Rectangle(0, 0, entireImage.Width, entireImage.Height), data, 0, entireImage.Width * entireImage.Height);
this.SetData<Color>(data);
}
public void Animate(GameTime gameTime)
{
int totalImageTime = _timeInterval * _numberOfImages;
int currentPoint = (int)gameTime.TotalGameTime.TotalMilliseconds % totalImageTime;
_currentImage = currentPoint / _timeInterval;
}
}
Usage is fairly simple:
1) declare it somewhere:
AnimatedTexture2D animatedTexture;
2) initiate it with your texture (i had a 2560x64 sequence of 40 64*64 images), where individual images are placed next to each other horizontally:
animatedTexture = new AnimatedTexture2D(Content.Load<Texture2D>(#"Textures\Loading"), 64, 40, 20);
3) in your Update() method, call:
animatedTexture.Animate(gameTime);
4) in your Draw() method, call:
SpriteBatch.Draw(animatedTexture, new Rectangle(20, 20, 64, 64), animatedTexture.DrawFromRectangle, Color.White);
Don't forget the DrawFromRectangle in part 4! (notice that the destination rectangle uses the declared individual part width, not the entire texture width which is in my test 2560 pixels)
Now, in your code you could forget the interval part, and the gametime part, and you could just use this instead of the default one!
Also, if you don't like my timing code (its ultra simple but lacks a way to reset the animation) change it so you have an elapsed time variable, and add to it like you do in your own code, and use that to change _currentImage. You could even make that variable public so you can use it to reset the animation (or set it to a specified point).
Of course, you could also make the default one an animated texture with only one frame so you can use the same code everywhere. Hope this helps!
You need to keep the last time Update(..) was called, and the interval should be... well.. an interval, that is, the difference between ElapsedGameTime and last call to update ElapsedGameTime.
Do it with a new member of your class (LastElapsedGameTimeUpdateCalled) or a static member of your sub.
If you know that every animation is going to have the same number of frames you could keep 3 variables per sprite (encapsulate in class for best results).
BaseFrame is an integer to hold a global animation number.
SubFrame is an offset in to the animation that holds which frame you are currently on.
FrameAccumulator to hold timing information.
Each time update is called, add the number of ms since the last update to the accumulator. Once the accumulator goes above your animation timing, increment SubFrame, and reset the accumulator. Check to see if subFrame is greater than the number of frames for each animation, and if it is, set it back to 0. You can get the real frame index from this by adding BaseFrame + Subframe. When you need to display a different animation just change the BaseFrame.
Lets say that each animation has 3 frames, and you have 2 total animations. You would have 6 total frames. RunLeft would be BaseFrame 0, and RunRight would be BaseFrame 3. That should easily give you the frame number to draw.
Been wrapping my head around this problem for a while and looking for solutions online to no effect.
Basically if I have a sprite for example located at (10,10) I want to move it to say (50,100) and the whole process to take 2 seconds or whatever duration I specify. What is the exact math behind this? I was using a distance based solution to determine speed but was just using a random modifier to control the process. I need something more precise to execute exactly over a set duration.
Any help on this issue would be greatly appreciated!
Assuming linear interpolation (i.e. moving in a straight line from start position to end position at a constant rate):
The vector from start to destination is destination - start, i.e. for your example (40,90).
If you want this to happen over two seconds you need to divide it by two to get the distance travelled per second, so (20,45) per second for your example.
To get the position at any given time, first record the start time and calculate the current time minus the start time in seconds. So if the animation started at 12:01:30.000 and it is now 12:01:31.500 then 1.5 seconds have past since the start of the animation.
To get the current location you add the start location to the movement per second vector * the time elapsed, so in my example:
(10,10) + (20,45) * 1.5 = (10,10) + (30, 67.5) = (40, 77.5)
It's just a thing of interpolation and time.
There is linear, sinus, quadratic, ...
Here is some more info and examples in actionscript: link
Take a closer look to jQuery's animation algorithms... maybe you can use some of the code.
http://code.jquery.com/jquery-1.6.1.js (search for "custom:" as a starting point).
You need a couple of pieces of information to do this, start location, end location, duration and elapsed time.
Here's an example in actionscript:
package {
import flash.utils.getTimer;
import flash.events.Event;
import flash.display.Shape;
import flash.geom.Point;
import flash.display.Sprite;
public class Mover extends Sprite {
private var circle :Shape;
private var start :Point;
private var end :Point;
private var duration :int;
public function Mover() {
// first we create something to move, like, a circle
circle = new Shape();
circle.graphics.beginFill(0xff00ff);
circle.graphics.drawCircle(0, 0, 20);
addChild(circle);
// start and end positions
start = new Point(0, 0);
end = new Point(100, 100);
// and finally, the duration, i'm using milliseconds
duration = 2000;
// this event handler will run each frame
addEventListener(Event.ENTER_FRAME, handleEnterFrame);
}
private function handleEnterFrame(event:Event):void {
// we figure out how much of the animation has elapsed by using getTimer
// should you want to use a start time, add it here
var progress:Number = getTimer() / duration;
// we need to clamp our progress so we don't under- or overshoot the target
if(progress < 0) progress = 0;
if(progress > 1) progress = 1;
// then it's a matter of setting the position
// we use the start position as a base and then gradually add in
// the difference between the start and the end
circle.x = start.x + (end.x - start.x) * progress;
circle.y = start.y + (end.y - start.y) * progress;
}
}
}
If you're not all that interested in the how and just want the results, I wholeheartedly recommend a tweening engine like TweenLite or any of the other myriad of them. Just stay clear of the one that comes with flash, it's a bit crap.