Showing posts with label sprite. Show all posts
Showing posts with label sprite. Show all posts

Wednesday, May 3, 2017

How to load sprite sheet with 5 rows and 5 columns top view in android?

Leave a Comment

I have a sprite sheet of 612x864 dimension with 5 rows and 5 columns .My problem is how can I load it and animate it? I want to move the cat sprite in y-axis only .I've already try but my code is not working properly. Here is my code.

In GameView.java

import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.view.SurfaceHolder; import android.view.SurfaceView;  public class GameView extends SurfaceView { private Bitmap bmp; private SurfaceHolder holder; private GameLoopThread gameLoopThread; private Sprite sprite;  public GameView(Context context) {     super(context);     gameLoopThread = new GameLoopThread(this);     holder = getHolder();     holder.addCallback(new SurfaceHolder.Callback() {          @Override         public void surfaceDestroyed(SurfaceHolder holder) {             boolean retry = true;             gameLoopThread.setRunning(false);             while (retry) {                 try {                     gameLoopThread.join();                     retry = false;                 } catch (InterruptedException e) {                 }             }         }          @Override         public void surfaceCreated(SurfaceHolder holder) {             gameLoopThread.setRunning(true);             gameLoopThread.start();         }          @Override         public void surfaceChanged(SurfaceHolder holder, int format,                                    int width, int height) {         }     });     bmp = BitmapFactory.decodeResource(getResources(), R.drawable.catsprite);     sprite = new Sprite(this,bmp); }  @Override protected void onDraw(Canvas canvas) {     canvas.drawColor(Color.BLACK);     sprite.onDraw(canvas); } } 

GameLoopThread.java

import android.graphics.Canvas;  public class GameLoopThread extends Thread { static final long FPS = 10; private GameView view; private boolean running = false;  public GameLoopThread(GameView view) {     this.view = view; }  public void setRunning(boolean run) {     running = run; }  @Override public void run() {     long ticksPS = 1000 / FPS;     long startTime;     long sleepTime;     while (running) {         Canvas c = null;         startTime = System.currentTimeMillis();         try {             c = view.getHolder().lockCanvas();             synchronized (view.getHolder()) {                 view.onDraw(c);             }         } finally {             if (c != null) {                 view.getHolder().unlockCanvasAndPost(c);             }         }         sleepTime = ticksPS-(System.currentTimeMillis() - startTime);         try {             if (sleepTime > 0)                 sleep(sleepTime);             else                 sleep(10);         } catch (Exception e) {}     } } } 

Sprite.java

import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect;  public class Sprite { private static final int BMP_ROWS = 5; private static final int BMP_COLUMNS = 5; private int x = 0; private int y = 0; private int ySpeed = 3; private GameView gameView; private Bitmap bmp; private int currentFrame = 1; private int width; private int height;  public Sprite(GameView gameView, Bitmap bmp) {     this.gameView = gameView;     this.bmp = bmp;     this.width = bmp.getWidth() / BMP_COLUMNS;     this.height = bmp.getHeight() / BMP_ROWS; }  private void update() {     if (y > gameView.getWidth() - width - y) {         ySpeed = -5;     }     if (y + y < 0) {         ySpeed = 5;     }     y = y + ySpeed;     currentFrame = ++currentFrame % BMP_COLUMNS; }  public void onDraw(Canvas canvas) {     update();     int srcX = currentFrame * width;     int srcY = 1 * height;     Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);     Rect dst = new Rect(x, y, x + width, y + height);     canvas.drawBitmap(bmp, src, dst, null); } } 

2 Answers

Answers 1

I'll recommend you to use this library. It's great for Sprite Animation. It has some limitations though, but it works fine.

Here is the code how I done it.

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.runningcat); int width = bitmap.getWidth(); int height = bitmap.getHeight();  int frameWidth = width / 5;    //you have 5 columns int frameHeight = height / 5;  //and 5 rows int frameNum = 25;             //there would be 25 images   SpriteSheetDrawer spriteSheetDrawer = new SpriteSheetDrawer(         bitmap,         frameWidth,         frameHeight,         frameNum)         .spriteLoop(true)         .frequency(2);   //change it as per your need   DisplayObject displayObject = new DisplayObject(); displayObject         .with(spriteSheetDrawer)         .tween()         .tweenLoop(true)         .transform(0, 0) //I have changed it according to my need, you can also do this by changing these values         .toX(4000, 0)    //this one too.         .end(); //In actual example, it's set as animation starts from one end of the screen and goes till the other one.   FPSTextureView textureView = (FPSTextureView) findViewById(R.id.fpsAnimation); textureView.addChild(displayObject).tickStart(); 

Answers 2

Problem is in src value that you're using in method. canvas.drawBitmap(bmp, src, dst, null); srcY should be zero. I've tested here.

private Bitmap character; private counter,charFrame; private RectF annonymousRectF; private Rect annonymousRect;  public Sprite() {      character=BitmapFactory.decodeResource(context.getResources(), R.drawable.flipchar2);      annonymousRect=new Rect();      annonymousRectF=new RectF(); }   public void update() {     counter++;     if(counter%5==0)         if(charFrame<NO_CHAR_FRAME-1)             charFrame++;         else             charFrame=0; }  public void draw(){     annonymousRect.set(charFrame*character.getWidth()/NO_CHAR_FRAME,0,(charFrame+1)*character.getWidth()/NO_CHAR_FRAME,character.getHeight());     annonymousRectF.set(-width*.015f,height*.35f,width*.5f,height*.58f);  //set value according to where you want to draw     canvas.drawBitmap(character, annonymousRect,annonymousRectF, null); } 
Read More

Wednesday, March 1, 2017

What is causing this card to change dimensions? [Video & Code]

Leave a Comment

I am programming a board game in Starling (Action Script 3). The Starling version that I am using has a class called Sprite3D, which allows me to conveniently and easily code the flipping of the cards used in this game. I am troubled by the fact that my card changes dimension when flipped, and I cannot find the source of the change.

All help is appreciated.

The problem can be viewed on this youtube video.

The code can be seen in full on github at this github page.

I will continue here with more detail... All the following information is covered in the video.

The Card class contains no visual information. It is a controller class. It does hold two sprites. One sprite fills the front face, and the other sprite fills the back face. The Card class also has a mask applied and dimension attributes so that the faces will be of equal size and shape.

The Card class also holds the animation code. The code to animate the card is very similar to the code used in a video found on the starling blog that shows how Stage3D can be used implemented in a 2D game of Memory very quickly and easily. The Card class animates the rotation by using a tween to change the card's rotationY property from 0 to PI and from PI to 0 on touch events. The error occurs during the flipping process, so I will include the flipping code here:

public function flip() : void {     _state = !(this._state);     if( this.animations ){         var tween : starling.animation.Tween = new Tween( this, 2, starling.animation.Transitions.EASE_OUT_BOUNCE );         var card : Card = this;         var didFlip : Boolean = false;         tween.animate("rotationY", this._state == Card.FACE_UP ? Math.PI : 0 );         tween.onUpdate = updateVisibility;         Starling.juggler.add( tween );     } } private function updateVisibility():void {     var sHelper:Vector3D = new Vector3D();     var card : Card = this;     stage.getCameraPosition( card, sHelper );     if( sHelper ){         this._front_face.visible = sHelper.z < 0;         this._back_face.visible = sHelper.z >= 0;     } } 

The FrontFace and BackFace classes both derive from the class CardFace. The CardFace class takes a card as a reference and sets a mask equal to the size and shape of the card's mask. This is likely redundant, as the card's mask should mask all children DisplayObjects, but we do it anyway.

The BackFace has text, a logo, a texture and a color.

The FrontFace does nothing. It is subclassed with specific behaviors and will convert a data object into a display layout.

In this case, we are subclassing FrontFace with ProfileFrontFace. ProfileFrontFace takes the card object and a profile data object as constructor arguments. The card object is passed to CardFace via super() calls, and the profile object is saved for later use.

When the ProfileFrontFace is added to the stage, the class extracts the title, income, and expenses from the profile data object. It creates text fields for each of these items. It also calculates a cash flow and creates a text field for this value. A background is created using a PNG texture, which is a simple white square, that is stretched over the whole face of the card's dimensions. Over this white square, we apply a color texture. After it is created, the background image is not altered. The code appears as follows:

//we remove the event listener so this function code is only executed once this.removeEventListener( Event.ADDED_TO_STAGE, onAddedToStage ); var width : int = this.cardWidth; /* 400 */ var height : int = this.cardHeight; /* 300 */ var bg : Image = new Image( Game.assets.getTexture("blank") ); /* start the background in the top left */ bg.x = 0; bg.y = 0; /* have the background fill the card dimension space */ bg.width = width; bg.height = height; /* apply a color so that the background is not pure white */ bg.color = ColorScheme.OPAL; /* add the background to the stage */ this.addChild( bg ); 

In the rest of the function, we create the text and display it. I am not including that code here for simplicity. In testing, I have removed that code and seen that it has no impact on the peculiar behavior that changes the dimensions of the card when flipped to the front face.

Has anyone seen a case where masks on a Sprite3D fail to perform as a mask?

Has anyone seen cases where a mask fails to perform on a regular Sprite object?

What about the Tween.animate() method might cause strange behavior when Tween is used to change the value of "rotationY" on an object?

Any and all answers will help. Thank you!

1 Answers

Answers 1

FIXED!!!!! I found it!

I discovered that the problem was not the front face. I had applied a mask to the card itself, which was the Sprite3D object. That mask was causing problems. When I removed it, the BackFace (a Sprite Object) expanded to the same size as the front face, and now when I set the card dimensions, both faces have equal sizing.

I have updated the card dimensions to 400x250 to match the original BackFace layout, and now everything is working well.

Tip: Set your masks on the Sprite objects and not the Sprite3D objects, when possible. That keeps the 2D manipulations on the 2D objects.

Read More

Saturday, March 12, 2016

Getting “giggly” effect when slowly moving a sprite

Leave a Comment

How do I remove this "giggly" effect when slowly moving a sprite?

I have tried adjusting Antialiasing values in QualitySettings and Filter Mode in ImportSettings in the Unity Editor but that doesn't change anything.

enter image description here

Ideally, I would like to keep the Filter Mode to Point (no filter) and anti aliasing turned on to 2x

enter image description here

The sprite is located inside a Sprite Renderer component of a GameObject.

I have uploaded my Unity Project here: http://www.filedropper.com/sprite

I really don't know how to fix the problem... Can anyone help with my personal project?

2 Answers

Answers 1

I cooked up a quick animation to demonstrate what's happening here:

Animation demonstrating source of ripple

The grid represents the output pixels of your display. I've overlaid on top of it the sliding sprite we want to sample, if we could render it with unlimited sub-pixel resolution.

The dots in the center of each grid cell represent their sampling point. Because we're using Nearest-Nieghbour/Point filtering, that's the only point in the texture they pay attention to. When the edge of a new colour crosses that sampling point, the whole pixel changes colour at once.

The trouble arises when the source texel grid doesn't line up with our output pixels. In the example above, the sprite is 16x16 texels, but I've scaled it to occupy 17x17 pixels on the display. That means, somewhere in every frame, some texels must get repeated. Where this happens changes as we move the sprite around.

Because each texel is rendered slightly larger than a pixel, there's a moment where it completely bridges the sampling points of two adjacent pixels. Both sampling points land within the same enlarged texel, so both pixels see that texel as the nearest one to sample from, and the texel gets output to the screen in two places.

In this case, since there's only a 1/16th scale difference, each texel is only in this weird situation for a frame or two, then it shifts to its neighbour, creating a ripple of doubled pixels that appears to slide across the image.

(One could view this as a type of moiré pattern resulting from the interaction of the texel grid and the sampling grid when they're dissimilar)

The fix is to ensure that you scale your pixel art so each texel is displayed at the size of an integer multiple of pixels.

Either 1:1

Animation showing ripple-free rendering at 1:1 scale

Or 2:1, 3:1...

Animation showing ripple-free rendering at 3:1 scale

Using a higher multiple lets the sprite move in increments shorter than its own texel size, without localized stretching that impacts the intended appearance of the art.

So: pay close attention to the resolution of your output and the scaling applied to your assets, to ensure you keep an integer multiple relationship between them. The blog post that CAD97 links has practical steps you can take to achieve this.

Edit: To demonstrate this in the Unity project you've uploaded, I modified the camera settings to match your pixels to units setting, and laid out the following test. The Mario at the top has a slightly non-integer texel-to-pixel ratio (1.01:1), while the Mario at the bottom has 1:1. You can see only the top Mario exhibits rippling artifacts:

Two Marios, one exhibiting artifacts

Answers 2

You might be interested in this blog post about making "pixel-perfect" 2D games in Unity.

Some relevant excerpts:

If you start your pixel game with all the default settings in Unity, it will look terrible!

The secret to making your pixelated game look nice is to ensure that your sprite is rendered on a nice pixel boundary. In other words, ensure that each pixel of your sprite is rendered on one screen pixel.

These other settings are essential to make things as crisp as possible.

On the sprite:

  • Ensure your sprites are using lossless compression e.g. True Color
  • Turn off mipmapping
  • Use Point sampling

In Render Quality Settings:

  • Turn off anisotropic filtering
  • Turn off anti aliasing

Turn on pixel snapping in the sprite shader by creating a custom material that uses the Sprite/Default shader and attaching it to the SpriteRenderer.

Also, I'd just like to point out that Unless you are applying Physics, Never Use FixedUpdate. Also, if your sprite has a Collider and is moving, it should have a Kinematic RigidBody attached even if you're never going to use physics, to tell the engine that the Collider is going to move.

Read More