I am using the background scrolling tutorial on xnadevelopment.com (modified to suit my requirement) to create a vertical scrolling loop for a game on windows phone 7.1. It seems like the background is flickering whenever the next image is drawn. Though I am using a single image for the loop, the flickering occurs even if multiple images are used. I have posted a youtube video showing the flicker that occurs at the top of the screen.
http://youtu.be/Ajdiw2zILq0
Below is the code used to create the loop:
Background class:
private List<string> _road;
private VericalBackgroundLoop _roadLoop;
private readonly Vector2 _roadSpeed = new Vector2(0, 300);
public void LoadContent(ContentManager contentManager)
{
_road = new List<string>
{
"Test\\Road_Bgnd",
"Test\\Road_Bgnd"
};
_roadLoop = new VericalBackgroundLoop();
_roadLoop.Initialize(_road, contentManager, Vector2.Zero, true);
}
public void Update(TimeSpan elapsedTime)
{
_roadLoop.Update(_roadSpeed, elapsedTime);
}
public void Draw(SpriteBatch spriteBatch)
{
_roadLoop.Draw(spriteBatch);
}
Background loop class:
private List<Sprite> _sprites;
private bool _isLoopDirectionTopToBottom;
private Vector2 _loopDirection;
public void Initialize(List<string> spriteNames, ContentManager contentManager, Vector2 loopStartPosition, bool isLoopDirectionTopToBottom)
{
_sprites = new List<Sprite>();
_isLoopDirectionTopToBottom = isLoopDirectionTopToBottom;
_loopDirection = new Vector2(0, -1);
// Build the sprite object's list
foreach (string spriteName in spriteNames)
{
Sprite sprite = new Sprite();
sprite.LoadContent(contentManager, spriteName);
_sprites.Add(sprite);
}
if (_isLoopDirectionTopToBottom)
{
// Set the initial position for the sprite objects
foreach (Sprite currentSprite in _sprites)
{
if (currentSprite == _sprites.First())
{
currentSprite.Position = loopStartPosition;
}
else
{
Sprite prevSprite = GetSpriteAtIndex(_sprites.IndexOf(currentSprite) - 1);
currentSprite.Position = new Vector2(0, prevSprite.Position.Y - prevSprite.Size.Height);
}
}
}
}
public void Update(Vector2 loopSpeed, TimeSpan elapsedTime)
{
if (_isLoopDirectionTopToBottom)
{
foreach (Sprite currentSprite in _sprites)
{
if (currentSprite == _sprites.First())
{
Sprite lastSprite = _sprites.Last();
if (currentSprite.Position.Y > (currentSprite.Size.Height))
{
currentSprite.Position.Y = lastSprite.Position.Y - lastSprite.Size.Height;
}
}
else
{
Sprite prevSprite = GetSpriteAtIndex(_sprites.IndexOf(currentSprite) - 1);
if (currentSprite.Position.Y > (currentSprite.Size.Height))
{
currentSprite.Position.Y = prevSprite.Position.Y - prevSprite.Size.Height;
}
}
// Update the sprite X position with the speed and time
currentSprite.Position -= _loopDirection * loopSpeed * (float)elapsedTime.TotalSeconds;
}
}
}
public void Draw(SpriteBatch spriteBatch)
{
foreach (Sprite sprite in _sprites)
{
sprite.Draw(spriteBatch);
}
}
private Sprite GetSpriteAtIndex(int index)
{
return _sprites[index];
}
I need help in figuring out why the flicker is occurring and why motion seems to be jerky and not smooth (it is a bit better on the device, but jerky nevertheless). IsFixedTimeStep is set to true in the game.cs class. Thank you.
EDIT : Seems like the flicker is not occuring if 3 or more images are used. This could be due to the first image not being placed back into the start position quickly enough. But am still trying to figure out whey the animation is still so jerky :(
You wouldn't be the first to report seeing flickers or stutters. Lots of posts on the App Hub forums about that. (glad you're finding luck using my tutorials/samples by the way!)
Here's an example of someone reporting what you're seeing -> http://forums.create.msdn.com/forums/t/30500.aspx
And here's the best answer I've seen to date from one of the XNA Framework developers ->
http://forums.create.msdn.com/forums/p/9934/53561.aspx#53561
Basically you've stumbled onto "a" solution, but as Shawn's post points out there's a variety of ways to fix the problem, it just depends on what's right for your game.
Related
I've just started learning Unity and encountered some problems.
Here I have a prefab object ParticleAlly with a parent ParticleAllies. The parent object rotates itself, and ParticleAlly rotates too, like a planet and satellites.
Besides, I also want to regenerate each ParticleAlly as soon as it is out of the camera. Then they are in different orbits with only the same angular velocity but in different positions. When it gets into and then get out of the camera, do that again.
The problem is, some ParticleAlly appeared in the middle of the camera directly after they are regenerated. I tried to let them not rendered until they get into the camera from outside. But it seems that SpriteRenderer.isvisible is true only when SpriteRenderer.enabled is true, so I cannot get know when to render them again. Then I tried to judge by position, but I don't know why it doesn't work at all.
I'm totally confused and wasted a whole morning on that. Sorry for my inaccurate description and term using.
It would be appreciated if you could provide me a solution and tell me something about Update(), the rendering, the position/localposition in rotation etc.
// in ParticleAlly
void Update() {
//Debug.Log(trans.localPosition.y);
if(trans.position.y <= globalSettings.RotationLocationY) {
Debug.Log("Under");
if(!isRefreshed) {
refresh();
}
sRender.enabled = true;
}
else {
if(sRender.isVisible) {
isRefreshed = false;
}
}
}
/// <summary>
/// Regenerate the particle
/// </summary>
void refresh() {
isRefreshed = true;
float height = Random.value * 3;
trans.localPosition = (new Vector3(0f, globalSettings.RotationLocationY - height, 0f));
//trans.RotateAround(trans.parent.localPosition, new Vector3(0f, 0f, 1f), globalSettings.getDegree() * Random.value);
trans.localRotation = Quaternion.Euler(new Vector3(0f, 0f, globalSettings.getDegree() * Random.value));
//sRender.enabled = false;
}
// in ParticleAllies
void Update() {
trans.localRotation = Quaternion.Euler(new Vector3(0f, 0f, globalSettings.getDegree()));
}
It's my first time asking here, the tabs are somehow broken in the code?
The issue with Renderer.isVisible is that
As you already noted it only can be true if the renderer is enabled
It can stay true even if the object is not visible itself but has some visual influence on the rendering (such as e.g. shadows)
In case the position would be enough you could simply use e.g.
public static class Extensions
{
pulic static bool IsInFrustum(this Camera camera, Vector3 worldPoint)
{
var screenPos = camera.WoldToscreenPoint(worldPoint);
return screenPos.z >= camera.nearClipPlane
&& screenPos.z <= camera.farClipPlane
&& screenPos.x >= 0
&& screenPos.x <= Screen.width
&& screenPos.y >= 0
&& screenPos.y <= Screen.height;
}
public static bool sInFrustum(this Vector3 worldPoint, Camera camera)
{
return camera.IsInFrustum(worldPoint);
}
}
and would do e.g.
someRenderer.enabled = yourCamera.IsInFrustum(someRenderer.transform.position);
or also
someRenderer.enabled = someRenderer.transform.position.IsInFrustum(yourCamera);
If a single position is not enough, you can get the camera frustum planes using GeometryUtility.CalculateFrustumPlanes and then check if some Bounds e.g. the Renderer.bounds fall within those using GeometryUtility.TestPlanesAABB.
Bounds are not completely accurate always of course but are probably the best approximation you can get.
public static class Extensions
{
public static bool IsInFrustum(this Renderer renderer, Camera camera)
{
var planes = GeometryUtility.CalculateFrustumPlanes(camera);
return GeometryUtility.TestPlanesAABB(planes, renderer.bounds);
}
public static bool IsInFrustum(this Camera camera, Renderer renderer)
{
return renderer.IsVisibleFrom(camera);
}
}
You can now either use on your camera e.g.
someRenderer.enabled = yourCamera.IsInFrustum(someRenderer);
or also
someRenderer.enabled = someRenderer.IsInFrustum(yourCamera);
So, firstly, my scene is made out of 9 empty objects each one having spikes that have animation to pop out of the floor. I am making a game where you should avoid spikes and other projectiles. I tested this first with sprite renderer and changing colors, it worked perfectly. But when I want to activate animations using trigger (animations start from empty game state and go to their animations, then after it finishes they return to normal). I've looked trough every thing I could think of and I could not solve this. It always starts animations for 4-6 different animations and start them at the same time, but for some reason: AFTER FIRST SHOWING, every single time after first time spikes appear, 2/3 out of 4/6 always show late but start at same time. Weirdly first time it always works greatly. Any thoughts on what may cause this?
void Update()
{
if (spikeTimer > 0)
spikeTimer -= Time.deltaTime;
if (spikeTimer<0)
{
Function();
spikeTimer = spikeCooldown;
}
}
public void Function()
{
int x = Random.Range(4, 6);
List<int> included = new List<int>();
while (included.Count < x)
{
int y = Random.Range(1, 10);
if (!included.Contains(y))
{
included.Add(y);
}
}
foreach (int i in included)
{
print("aktiviran je broj" + i);
Spikes[i - 1].GetComponent<Spike>().ActivateSpike();
}
}
Now this is the ActivateSpike method that all Spikes in the scene contain
public void ActivateSpike()
{
SpriteRenderer sr = gameObject.GetComponent<SpriteRenderer>();
if (sr.color != Color.black)
{
sr.color = Color.black;
}
else
sr.color = Color.red;
/* Animator animator = gameObject.GetComponent<Animator>();
animator.SetTrigger("Activate");*/
}
You can see that I tried changing the sprite to square and changing its color, and it works perfectly...
Looking for a bit of help to see how I can make this algorithm a little better. So I have some code for a pan tool that moves the camera based on the user dragging the mouse to move the camera around. However it is really jumpy unless it is done in really short drags. I.e. the objects in the scene appear to vibrate, which is more likely to be the camera and canvas 'vibrating' rather than the objects themselves.
The code works by toggling a dragging boolean using the SystemEvent methods OnPointerDown and OnPointerUp and assigns a MouseStart Vector3 in world coordinates and also a CameraStart Vector3.
public void OnPointerDown(PointerEventData EventData)
{
if (!dragging)
{
dragging = true;
MouseStart = new Vector3(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y, 0f);
CameraStart = TheCamera.transform.position;
}
}
public void OnPointerUp(PointerEventData EventData)
{
if (dragging)
{
dragging = false;
}
}
Then in the update loop while the dragging variable is true, xChange and yChange float values are determined based on the current mouse position compared to the original mouse position, the camera position is then adjusted according to these. My thought process was that because it is relative to a fixed MouseStart (because it is only changed in the single frame where the pointer is clicked and dragging = 0) that if I were to drag and then say keep the mouse still, there would be no change in coordinates as it'd be repeatedly putting the Camera in the same position. The full code looks like this:
private bool dragging;
private string CurrentTool;
private ButtonController[] DrawingTools;
public Camera TheCamera;
public Vector3 MouseStart;
public Vector3 CameraStart;
public float sensitivity;
// Use this for initialization
void Start () {
TheCamera = FindObjectOfType<Camera>();
DrawingTools = FindObjectsOfType<ButtonController>();
}
// Update is called once per frame
void Update () {
for (int i = 0; i < DrawingTools.Length; i++)
{
if (DrawingTools[i].Pressed)
{
CurrentTool = DrawingTools[i].gameObject.name;
}
}
if (dragging && CurrentTool == "PanTool Button")
{
float xChange;
float yChange;
Vector3 MousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (MousePosition.x > MouseStart.x)
{
xChange = -Mathf.Abs(MousePosition.x - MouseStart.x);
}
else
{
xChange = Mathf.Abs(MousePosition.x - MouseStart.x);
}
if (MousePosition.y > MouseStart.y)
{
yChange = -Mathf.Abs(MousePosition.y - MouseStart.y);
}
else
{
yChange = Mathf.Abs(MousePosition.y - MouseStart.y);
}
TheCamera.transform.position = new Vector3(CameraStart.x + xChange*sensitivity, CameraStart.y + yChange*sensitivity, CameraStart.z);
}
}
public void OnPointerDown(PointerEventData EventData)
{
if (!dragging)
{
dragging = true;
MouseStart = new Vector3(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y, 0f);
CameraStart = TheCamera.transform.position;
}
}
public void OnPointerUp(PointerEventData EventData)
{
if (dragging)
{
dragging = false;
}
}
Any help is appreciated, thanks.
EDIT: Just to clarify this is a 2d environment
This is happening because the Camera from which you are determining the world position of the mouse is being updated every frame according to the world position of the mouse, which causes a feedback loop (and therefore noise + jitter).
You can reduce noise from the feedback loop by smoothing the Camera's movement over time (effectively a low pass), or try to remove the feedback loop entirely by altering your calculations so the camera position and target position (mouse) don't rely on each other - although I'm not sure how to go about that if it's actually possible for your intent.
Check out Vector3.SmoothDamp.
Gradually changes a vector towards a desired goal over time.
The vector is smoothed by some spring-damper like function, which will
never overshoot. The most common use is for smoothing a follow camera.
I'm developing an application in Unity with the Google CardbBoard Plugin, and I tried to fade in/out the screen when passing between scenes, I've worked with this example drawing a texture in the GUI object:
GUI.color = new Color (GUI.color.r, GUI.color.g, GUI.color.b, alpha);
Texture2D myTex;
myTex = new Texture2D (1, 1);
myTex.SetPixel (0, 0, fadeColor);
myTex.Apply ();
GUI.DrawTexture (new Rect (0, 0, Screen.width, Screen.height), myTex);
if (isFadeIn)
alpha = Mathf.Lerp (alpha, -0.1f, fadeDamp * Time.deltaTime);
else
alpha = Mathf.Lerp (alpha, 1.1f, fadeDamp * Time.deltaTime);
if (alpha >= 1 && !isFadeIn) {
Application.LoadLevel (fadeScene);
DontDestroyOnLoad(gameObject);
} else if (alpha <= 0 && isFadeIn) {
Destroy(gameObject);
}
The code I worked with is from this page: Video Tutorial, Example downloads, and it worked fine in a Unity game without the Cardboard plugin, but in my current project the same way to use this code is not working. The only difference is the use of the Cardboard plugin.
Is there any specific Cardboard object I must use instead of GUI or another way to draw a texture?
As per the Google Cardboard docs, You need to have GUI elements exist in 3D space infront of the camera so they are replicated in each eye.
I'll share my solution of how I did it. Note that What I've done is have a single instance of the Cardboard Player Prefab spawn when my game starts and persist throughout all my levels via DontDestoryOnLoad(), rather than have a seperate instance in each level.
This allows for settings to be carried over to each loaded level and Fade out and Fade in the screen.
I accomplished a screen fader by creating a World Space Canvas that is parented to the Cardboard prefab's "Head" object so it follows gaze, And put a Black Sprite image that covers the entire Canvas which blocks the players view when the Black Sprite is visible.
This script attached to my Player Prefab allows me to first fade out the screen (call FadeOut()), Load a new level (set LevelToLoad to the level index you want to load), then Fade in the screen after the new level is loaded.
By default it uses the Async way of loading levels, To allow for loading Bars, But you can set UseAsync to false to load levels via Application.LoadLevel()
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class LoadOperations: MonoBehaviour {
public Image myImage;
// Use this for initialization
public bool UseAsync;
private AsyncOperation async = null;
public int LevelToLoad;
public float FadeoutTime;
public float fadeSpeed = 1.5f;
private bool fadeout;
private bool fadein;
public void FadeOut(){
fadein= false;
fadeout = true;
Debug.Log("Fading Out");
}
public void FadeIn(){
fadeout = false;
fadein = true;
Debug.Log("Fading In");
}
void Update(){
if(async != null){
Debug.Log(async.progress);
//When the Async is finished, the level is done loading, fade in the screen
if(async.progress >= 1.0){
async = null;
FadeIn();
}
}
//Fade Out the screen to black
if(fadeout){
myImage.color = Color.Lerp(myImage.color, Color.black, fadeSpeed * Time.deltaTime);
//Once the Black image is visible enough, Start loading the next level
if(myImage.color.a >= 0.999){
StartCoroutine("LoadALevel");
fadeout = false;
}
}
if(fadein){
myImage.color = Color.Lerp(myImage.color, new Color(0,0,0,0), fadeSpeed * Time.deltaTime);
if(myImage.color.a <= 0.01){
fadein = false;
}
}
}
public void LoadLevel(int index){
if(UseAsync){
LevelToLoad= index;
}else{
Application.LoadLevel(index);
}
}
public IEnumerator LoadALevel() {
async = Application.LoadLevelAsync(LevelToLoad);
yield return async;
}
}
The GUI, GUILayout and Graphics do not work in VR. No 2d direct to screen will work properly.
You should render in 3d, easiest thing to do is to put a sphere around the camera (or even better, two spheres around each eye) and animate their opacity.
I have an object that will fire out projectiles, I was trying to use a list to spawn in the Rockets(projectiles) so I could delete them when they collide with an object. So I first create List<Rectangle> Rockets; I then add in a function for the rockets to be spawned in and fired constantly:
if (Time > 0.2)
{
Time = 0;
Rockets.Add(new Rectangle((int)Position.X, (int)Position.Y, rocketTexture.Width, rocketTexture.Height));
}
I then try to update them so they will move across the screen by doing a foreach:
foreach (Rectangle r in Rockets)
{
}
Question
This is where I get stuck, how do I call upon the x and y value inside the list of each Rocket so i can move it across the screen?
I may be thinking too hard about this and there is an easier way to create a large amount of projectiles and have them despawn when colliding with a way or when they go too far.
In game development, you'd rather implement a Rocket class with a update() method, in which you'd move the rocket by some speed_x and speed_y attribute. You would then in your main run() method check collisions by calling Rocket.getRect() (or just a .Rect property, which could be implemented in a parent class Entity or something).
That being said, i may not have understood the problem.
Here's a code example, hope it helps
class Rocket
{
int _life;
public Rocket(Vector2 position, Vector2 direction)
{
_position = position;
_direction = direction;
//life of rocket. Once it reaches zero the rocket is removed.
_life = 100;
}
Vector2 _position
public Vector2 Position
{
get
{
return _position;
}
}
Vector2 _velocity;
Vector2 Velocity
{
get
{
return _velocity;
}
}
public int Life
{
get
{
return _life;
}
}
public void Update(World world)
{
_life--;
_position += _velocity;
//could check for collisions here, eg:
foreach (Ship ship in world.Ships)
{
if (Intersects(ship))
{
//collision!
//destroy this rocket
_life = 0;
//damage the ship the rocket hit
ship.ApplyDamage(10);
return;
}
}
}
}
class Game
{
List<Rocket> _rockets = new List<Rocket>();
List<Rocket> _deadRockets = new List<Rocket>();
void Update(GameTime gameTime)
{
//.ToArray() is used here because the .net list does not allow items to be removed while iterating over it in a loop.
//But we want to remove rockets when they are dead. So .ToArray() means we are looping over the array not the
//list, so that means we are free to remove items from the list. basically it's a hack to make things simpler...
foreach (Rocket rocket in _rockets.ToArray())
{
//world is an object that contains references to everything on the map
//so that the rocket has access to that stuff as part of it's update
rocket.Update( world );
//if the rocket has run out of life then remove it from the list
if (rocket.Life <= 0)
_rockets.Remove(rocket);
}
}
void FireRocket(Vector2 from, Vector2 direction)
{
Rocket newRocket = new Rocket(from, direction);
_rockets.Add(newRocket);
}
}
do a for loop instead of a foreach loop. I also recommend using arrays(and make a Rocket class instead of just Vector2s).
for (int i = 0; i < Rockets.Count; i++)
{
Rockets[i] = new Rectangle(Rockets[i].X + 20, Rockets[i].Y + 20);
}