textview object is keeping shaky all the time in sceneform - arcore

By using the code below, the textView is always face the camera. However, the textview object is keeping shaky all the time. Is that possible to add anchor with the code below to keep the textview object steady and static while rotating the phone?
I have tried to render a textview object in the scene and always facing to camera.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.sceneform_arfragment);
arFragment.getPlaneDiscoveryController().hide();
arFragment.getPlaneDiscoveryController().setInstructionView(null);
arFragment.getArSceneView().getPlaneRenderer().setEnabled(false);
node = new Node();
node.setParent(arFragment.getArSceneView().getScene());
node.setLocalPosition(new Vector3(0f, 0f, -1f));
ViewRenderable.builder()
.setView(this, R.layout.card)
.build()
.thenAccept(renderable -> {
node.setRenderable(renderable);
TextView textView = (TextView) renderable.getView();
textView.setText("Hello Sceneform");
});
arFragment.getArSceneView().getScene().addOnUpdateListener(this::onSceneUpdate);}
private void onSceneUpdate(FrameTime frameTime) {
arFragment.onUpdate(frameTime);
Vector3 cameraPosition = arFragment.getArSceneView().getScene().getCamera().getWorldPosition();
Vector3 cardPosition = node.getWorldPosition();
Vector3 direction = Vector3.subtract(cameraPosition, cardPosition);
Quaternion lookRotation = Quaternion.lookRotation(direction, Vector3.up());
node.setWorldRotation(lookRotation);
}
My expected result is the textview object facing to camera without shaky .

Related

Sceneform ARCore Android studio

I am developing an AR app that allow you to move a ball by swiping the screen. I am able to detect the swipe but I am unsure how I can move the ball. so I want the ball to move from one position to another based on how long the screen is swipe. so when you swipe the ball is moved like been thrown.
Can any one help me out with this. thanks
To move a renderable, you can delete it at the old position and place it at the new one. Here is an example - this is button driven rather than swipe driven, but the movement can be used similarly. The code below works on the currently selected anchorNode - i.e. the user can select different nodes to move.
//Add a listener for the left button
FloatingActionButton leftButtom = findViewById(R.id.left_button);
leftButtom.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Move the anchor left
Log.d(TAG,"Moving anchor left");
if (currentSelectedAnchorNode != null) {
//Get the current Pose and transform it then set a new anchor at the new pose
Session session = arFragment.getArSceneView().getSession();
Anchor currentAnchor = currentSelectedAnchorNode.getAnchor();
Pose oldPose = currentAnchor.getPose();
Pose newPose = oldPose.compose(Pose.makeTranslation(-0.05f,0,0));
currentSelectedAnchorNode = moveRenderable(currentSelectedAnchorNode, newPose);
}
}
});
private AnchorNode moveRenderable(AnchorNode markAnchorNodeToMove, Pose newPoseToMoveTo) {
//Move a renderable to a new pose
if (markAnchorNodeToMove != null) {
arFragment.getArSceneView().getScene().removeChild(markAnchorNodeToMove);
anchorNodeList.remove(markAnchorNodeToMove);
} else {
Log.d(TAG,"moveRenderable - markAnchorNode was null");
return null;
}
Frame frame = arFragment.getArSceneView().getArFrame();
Session session = arFragment.getArSceneView().getSession();
Anchor markAnchor = session.createAnchor(newPoseToMoveTo.extractTranslation());
AnchorNode newMarkAnchorNode = new AnchorNode(markAnchor);
newMarkAnchorNode.setRenderable(andyRenderable);
newMarkAnchorNode.setParent(arFragment.getArSceneView().getScene());
anchorNodeList.add(newMarkAnchorNode);
return newMarkAnchorNode;
}

How can I do processing on every frame using Sceneform?

I want to update my data associated with anchors that are updated each frame. How do I get the frame from ArSceneView for every frame?
The ArSceneView updates the ARCore Frame object before drawing the scene. You can access the frame by calling getArFrame() from a method registered with setOnUpdateListener().
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.sceneView = (ArSceneView) findViewById(R.id.scene_view);
sceneView.getScene().setOnUpdateListener((this::onSceneUpdate));
}
private void onSceneUpdate(FrameTime updatedTime) {
Frame frame = sceneView.getArFrame();
Collection<Anchor> updatedAnchors = frame.getUpdatedAnchors();
for (Anchor anchor : updatedAnchors) {
// Handle updated anchors...
}
}

Resize UI after keyboard appears. Issues with dimensions and sizes

I want to resize a UIView (e.g. TextField, UIGridView, ...) after the keyboard appears. Getting the appropriate events isn't the issue. I really stock by calculating the delta to shrink my view depending on the height of the keyboard.
If I have my iPad in front of me in portrait mode all calculations happens as expected. But If my device is in landscape mode or upside down, I'm really struggling getting the right dimensions! Some view frames/bounds aren't converted (in landscape mode is the height still higher then its width). Other views are translated depending if I've started my app already in landscape mode. The next challenge is working with consistent size measures. Sometimes the dimensions are like the real pixels (for a new iPad 2048) sometimes the scale factor isn't considered (for a new iPad 1024).
Any other idea how to the the correct frame size? Or are there any helpers which recognise the current orientation and provides me with the effective sizes?
My current code to achieve my expected behaviour is like this:
MyViewController
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
// My code...
AppDelegate.CurrentDelegate.KeyboardAppeared += KeyboardAppeared;
AppDelegate.CurrentDelegate.KeyboardDisappeared += KeyboardDisappeared;
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
AppDelegate.CurrentDelegate.KeyboardAppeared -= KeyboardAppeared;
AppDelegate.CurrentDelegate.KeyboardDisappeared -= KeyboardDisappeared;
}
private void KeyboardAppeared(object sender, KeyboardEventArgs e)
{
if (_keyboardButton != null)
_keyboardButton.Enabled = true;
var frame = LayoutHelper.RectangleForKeyboardAppearance(_textField, View.Window, e.Height);
LayoutHelper.ResizeViewForKeyboard(_textField, frame);
}
private void KeyboardDisappeared(object sender, EventArgs e)
{
if (_keyboardButton != null)
_keyboardButton.Enabled = false;
var frame = View.Bounds;
LayoutHelper.ResizeViewForKeyboard(_textField, frame);
}
MyHelperClass
public static RectangleF RectangleForKeyboardAppearance(UIView view, float windowHeight, float keyboardHeight)
{
var topOfKeyboard = windowHeight - keyboardHeight; // Obere linke Ecke der Tastatur auf den Bildschirm bezogen
var viewHeightWindow1 = view.ConvertPointFromView(new PointF(0, topOfKeyboard), null);
var frame = new RectangleF(view.Frame.X, view.Frame.Y, view.Frame.Width, (viewHeightWindow1.Y + view.Bounds.Y));
return frame;
}
public static void ResizeViewForKeyboard(UIView view, RectangleF frame)
{
UIView.BeginAnimations("viewMovementForKeyboard");
UIView.SetAnimationBeginsFromCurrentState(true);
UIView.SetAnimationDuration(0.3f);
view.Frame = frame;
UIView.CommitAnimations();
}

Sprite walking and background moving too: XNA

I would like to make a simple thing in XNA where the background would move when the character moves to the right.
Any ideas how to do it?
thanks
I think you mean like in the game Mario!
Using Scrolling.
Create the game class.
Load resources as described in the procedures of Drawing a Sprite.
Load the background texture.
private ScrollingBackground myBackground;
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
myBackground = new ScrollingBackground();
Texture2D background = Content.Load<Texture2D>("starfield");
myBackground.Load(GraphicsDevice, background);
}
Determine the size of the background texture and the size of the screen.
The texture size is determined using the Height and Width properties, and the screen size is determined using the Viewport property on the graphics device.
Using the texture and screen information, set the origin of the texture to the center of the top edge of the texture, and the initial screen position to the center of the screen.
// class ScrollingBackground
private Vector2 screenpos, origin, texturesize;
private Texture2D mytexture;
private int screenheight;
public void Load( GraphicsDevice device, Texture2D backgroundTexture )
{
mytexture = backgroundTexture;
screenheight = device.Viewport.Height;
int screenwidth = device.Viewport.Width;
// Set the origin so that we're drawing from the
// center of the top edge.
origin = new Vector2( mytexture.Width / 2, 0 );
// Set the screen position to the center of the screen.
screenpos = new Vector2( screenwidth / 2, screenheight / 2 );
// Offset to draw the second texture, when necessary.
texturesize = new Vector2( 0, mytexture.Height );
}
To scroll the background, change the screen position of the background texture in your Update method.
This example moves the background down 100 pixels per second by increasing the screen position's Y value.
protected override void Update(GameTime gameTime)
{
...
// The time since Update was called last.
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
// TODO: Add your game logic here.
myBackground.Update(elapsed * 100);
base.Update(gameTime);
}
The Y value is kept no larger than the texture height, making the background scroll from the bottom of the screen back to the top.
public void Update( float deltaY )
{
screenpos.Y += deltaY;
screenpos.Y = screenpos.Y % mytexture.Height;
}
// ScrollingBackground.Draw
Draw the background using the origin and screen position calculated in LoadContent and Update.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
myBackground.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
In case the texture doesn't cover the screen, another texture is drawn. This subtracts the texture height from the screen position using the texturesize vector created at load time. This creates the illusion of a loop.
public void Draw( SpriteBatch batch )
{
// Draw the texture, if it is still onscreen.
if (screenpos.Y < screenheight)
{
batch.Draw( mytexture, screenpos, null,
Color.White, 0, origin, 1, SpriteEffects.None, 0f );
}
// Draw the texture a second time, behind the first,
// to create the scrolling illusion.
batch.Draw( mytexture, screenpos - texturesize, null,
Color.White, 0, origin, 1, SpriteEffects.None, 0f );
}

Newly loaded sprites not behaving properly in XNA 4.0

Here is the code for a project im working on, where an enemy moves back and forth at the bottom of the screen.
class enemy1
{
Texture2D texture;
public Vector2 position;
bool isAlive = false;
Random rand;
int whichSide;
public enemy1(Texture2D texture, Vector2 position)
{
this.texture = texture;
this.position = position;
}
public void Update()
{
if (isAlive)
{
if (whichSide == 1)
{
position.X += 4;
if (position.X > 1000 + texture.Width)
isAlive = false;
}
if (whichSide == 2)
{
position.X -= 4;
if (position.X < 0)
isAlive = false;
}
}
else
{
rand = new Random();
whichSide = rand.Next(1, 3);
SetInStartPosition();
}
}
private void SetInStartPosition()
{
isAlive = true;
if (whichSide == 1)
position = new Vector2(0 - texture.Width, 563 - texture.Height);
if (whichSide == 2)
position = new Vector2(1000 + texture.Width, 563 - texture.Height);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
}
Now i want there to be a few enemys going back and forth but they start at differant positions so it looks like there is a few enemys going back and forth at the bottom of the screen. I have managed to draw a few other enemies on the screen, except they do not behave like the first enemy. They just are pictures on a screen not moving anywhere. So now all i have is the hero moving around and one enemy at the bottom of the screen, along with 5 other enemys sitting at the top of the screen doing nothing. How do i easily add a new sprite from a class that has the same behavior, at any time, while not making a billion variables to store them in?
Generally it's a good idea to have similar logic contained within the proper class, so if all Sprites where to do the same thing, then all you would need to do is put your movement code inside a public method and then call that method inside Update().
So, if your Sprite class looks something like this:
public class Sprite
{
private Vector2 Position;
public Sprite(Texture2D texture, Vector2 position)
{
Position = position;
}
//then just add this
public void MoveSprite(int amount)
{
position.X += amount;
}
}
Now, the object name "Sprite" is pretty generic, you will more than likely have many "Sprites" in your game.
So you're going to want to follow good OOP practices and maybe name this specific sprite something different and then have it derive from this class we're looking at right now. (But i'm not going to make design decisions for you)
This was a vague question, but that's my best shot at an answer for you.

Resources