I have quite easy class that draws circles. I'm giving the parameter, view calculates the rest. All I want to give some delay and fade effect for each during draw to canvas. I reviewed a few articles about animators and handlers but I couldn't figure out. Please, show me some implementations. Thanks.
#Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
int w = getWidth();
int pl = getPaddingLeft();
int pr = getPaddingRight();
int totalWidth = w - (pl + pr);
major = totalWidth / circleCount;
radius = major / 2;
startPoint = totalWidth / (circleCount * 2);
for (int i = 0; i < circleCount; i++) {
canvas.drawCircle(startPoint + major * i, radius, radius, paint);
}
}
Here's a simple alpha animation of a button view [it makes the button blink](it's not so hard ;O) ):
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
final Animation animation = new AlphaAnimation(1, 0); // Change alpha from fully visible to invisible
animation.setDuration(500); // duration - half a second
animation.setInterpolator(new LinearInterpolator()); // do not alter animation rate
animation.setRepeatCount(Animation.INFINITE); // Repeat animation infinitely
animation.setRepeatMode(Animation.REVERSE); // Reverse animation at the end so the button will fade back in
final Button btn = (Button) findViewById(R.id.but4);//replace this with your view
btn.startAnimation(animation);
You could use the setAlpha(int a) method from the Paint class.
It should work when you do it on a separate Thread with a little time delay in a loop where you count down from 255 to 0.
Here is a code sample where I tried this for earlier versions of Android some years ago :
private final int FADE_TIME = 10; // modify to your needs
private void fade() {
new Thread(new Runnable() {
#Override
public void run() {
try {
int i = 255;
while (i >= 0) {
paint.setAlpha(i);
Thread.sleep(FADE_TIME);
i--;
}
} catch (InterruptedException e) {
// do something in case of interruption
}
}
}).start();
}
Nowadays I would probably use a Handler with postDelayed() for this job, but this should give you an impression of how it can be done.
Related
I am developing a game in AndEngine and I want to attach a sprite to a parallax background (on my main menu) BUT I don't want the sprite to be repeated (which is what is currently happening).
I have tried this (below) which works but I use the sprites in the game so when I come back to the main menu, the sprites will have moved (I tried resetting the sprites but doesn't seem to be working).
Sprite playerCar = new Sprite(playerX, playerY,
mResourceManager.mPlayerCarTextureRegion,
mVertexBufferObjectManager);
playerCar.setRotation(-15);
attachChild(playerCar);
What I want to do is the following:
Define my sprite as normal:
Sprite playerCar = new Sprite(playerX, playerY,
mResourceManager.mPlayerCarTextureRegion,
mVertexBufferObjectManager);
playerCar.setRotation(-15);
Then attach it to my background:
ParallaxBackground menuParallaxBackground = new ParallaxBackground(0,
0, 0);
menuParallaxBackground.attachParallaxEntity(new ParallaxEntity(0,
new Sprite(0, SCREEN_HEIGHT
- mResourceManager.mParallaxLayerRoad.getHeight(),
mResourceManager.mParallaxLayerRoad,
mVertexBufferObjectManager)));
menuParallaxBackground.attachParallaxEntity(new ParallaxEntity(0,
playerCar));
Which also works but the car keeps on repeating which I do not want.
Any help would be appreciated! Thanks.
Problem was because of the onDraw method on the ParallaxEntity class in the ParallaxBackground class. There was a loop around where the sprites get drawn that keeps going until the sprites fill up the width of the screen. I simply created a custom class and removed the while loop so I could use it for my Main Menu.
ParallaxEntity onDraw code before:
public void onDraw(final GLState pGLState, final Camera pCamera, final float pParallaxValue) {
pGLState.pushModelViewGLMatrix();
{
final float cameraWidth = pCamera.getWidth();
final float shapeWidthScaled = this.mAreaShape.getWidthScaled();
float baseOffset = (pParallaxValue * this.mParallaxFactor) % shapeWidthScaled;
while(baseOffset > 0) {
baseOffset -= shapeWidthScaled;
}
pGLState.translateModelViewGLMatrixf(baseOffset, 0, 0);
float currentMaxX = baseOffset;
do {
this.mAreaShape.onDraw(pGLState, pCamera);
pGLState.translateModelViewGLMatrixf(shapeWidthScaled, 0, 0);
currentMaxX += shapeWidthScaled;
} while(currentMaxX < cameraWidth);
}
pGLState.popModelViewGLMatrix();
}
my CustomParallaxEntity onDraw code after (notice the last while loop removed):
public void onDraw(final GLState pGLState, final Camera pCamera,
final float pParallaxValue) {
pGLState.pushModelViewGLMatrix();
{
final float shapeWidthScaled = this.mAreaShape.getWidthScaled();
float baseOffset = (pParallaxValue * this.mParallaxFactor)
% shapeWidthScaled;
while (baseOffset > 0) {
baseOffset -= shapeWidthScaled;
}
pGLState.translateModelViewGLMatrixf(baseOffset, 0, 0);
this.mAreaShape.onDraw(pGLState, pCamera);
pGLState.translateModelViewGLMatrixf(shapeWidthScaled, 0, 0);
}
pGLState.popModelViewGLMatrix();
}
Thanks to the comments on my question for helping me figure out a solution.
OK for sake of argument and simplicity this code here has a rectangle sprite/texture that shoots(cuz it's a gun) upwards. And an enemy rectangle/sprite/texture the spawns downwards. Then the player detects if it hits a enemy. When the player hits an enemy I get an out of bounds exception -1
package com.TheGame.Pack;
import java.util.Iterator;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.TimeUtils;
public class GameScreen implements Screen {
final MasterClass game;
Texture FleetTexture;
Texture PlayerTexture;
Texture ShootingTexture;
OrthographicCamera camera;
Rectangle Player;
Array<Rectangle> Emma;
Array<Rectangle> Shooting;
long EmmaSpawnTime;
long ShootingTime;
public static int EmmaKilled = 0;
public GameScreen(final MasterClass gam) {
this.game = gam;
// load the images for the droplet and the Player, 64x64 pixels each
FleetTexture = new Texture(Gdx.files.internal("cirA.png")); //Enemies
PlayerTexture = new Texture(Gdx.files.internal("BoxA.png"));
ShootingTexture = new Texture(Gdx.files.internal("gun.png"));
// load the drop sound effect and the rain background "music"
// dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"));
// rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"));
// rainMusic.setLooping(true);
// create the camera and the SpriteBatch
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
// create a Rectangle to logically represent the Player
Player = new Rectangle();
Player.x = 800 / 2 - 64 / 2; // center the Player horizontally
Player.y = 20; // bottom left corner of the Player is 20 pixels above
// the bottom screen edge
Player.width = 40;
Player.height = 30;
// create the Emma array and spawn the first EmmaInArray
Emma = new Array<Rectangle>();
Shooting = new Array<Rectangle>();
spawnEmma();
}
private void spawnEmma() {
Rectangle EmmaInArray = new Rectangle();
EmmaInArray.x = MathUtils.random(0, 800 - 64);
EmmaInArray.y = 480;
EmmaInArray.width = 40;
EmmaInArray.height = 30;
Emma.add(EmmaInArray);
EmmaSpawnTime = TimeUtils.nanoTime();
}
private void spawnShooting(){
Rectangle ShootingInArray = new Rectangle();
ShootingInArray.x = Player.x;
ShootingInArray.y = Player.y;
ShootingInArray.width = 40;
ShootingInArray.height = 30;
Shooting.add(ShootingInArray);
ShootingTime = TimeUtils.nanoTime();
}
#Override
public void render(float delta) {
// clear the screen with a dark blue color. The
// arguments to glClearColor are the red, green
// blue and alpha component in the range [0,1]
// of the color to be used to clear the screen.
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// tell the camera to update its matrices.
camera.update();
// tell the SpriteBatch to render in the
// coordinate system specified by the camera.
game.batch.setProjectionMatrix(camera.combined);
// begin a new batch and draw the Player and
// all drops
game.batch.begin();
game.font.draw(game.batch, "Drops Collected: " + EmmaKilled, 0, 480);
game.batch.draw(PlayerTexture, Player.x, Player.y, Gdx.graphics.getWidth() / 20,
Gdx.graphics.getHeight()/ 20);
for (Rectangle EmmaInArray : Emma) {
game.batch.draw(FleetTexture, EmmaInArray.x, EmmaInArray.y);
}
for(Rectangle ShootingInArray : Shooting){
game.batch.draw(ShootingTexture, ShootingInArray.x, ShootingInArray.y);
ShootingInArray.y +=10;
}
game.batch.end();
// process user input
if (Gdx.input.isTouched()) {
Vector3 touchPos = new Vector3();
touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
Player.x = touchPos.x - 64 / 2;
}
if (Gdx.input.isKeyPressed(Keys.LEFT))
Player.x -= 400 * Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Keys.RIGHT))
Player.x += 400 * Gdx.graphics.getDeltaTime();
// make sure the Player stays within the screen bounds
if (Player.x < 0)
Player.x = 0;
if (Player.x > 800 - 64)
Player.x = 800 - 64;
// check if we need to create a new EmmaInArray
if (TimeUtils.nanoTime() - EmmaSpawnTime > 100000000){
spawnEmma();
}
if(TimeUtils.nanoTime() - ShootingTime > 100000000){
spawnShooting();
}
// move the Emma, remove any that are beneath the bottom edge of
// the screen or that hit the Player. In the later case we play back
// a sound effect as well.
Iterator<Rectangle> EmmaIterator = Emma.iterator();
while (EmmaIterator.hasNext()) {
Rectangle EmmaInArray = EmmaIterator.next();
EmmaInArray.y -= 200 * Gdx.graphics.getDeltaTime();
if (EmmaInArray.y + 64 < 0){
EmmaIterator.remove();
}
Iterator<Rectangle> ShootingIterator = Shooting.iterator();
while(ShootingIterator.hasNext()){
Rectangle ShootingInArray = ShootingIterator.next();
// ShootingInArray.y += 200 * Gdx.graphics.getDeltaTime();
if(ShootingInArray.y > 480){
ShootingIterator.remove();
}
if(EmmaInArray.overlaps(ShootingInArray)){
ShootingIterator.remove();
EmmaIterator.remove();
}
if (Player.overlaps(EmmaInArray)) {
EmmaKilled++;
game.setScreen(game.HS);
// dropSound.play();
if I comment out EmmaIterator.remove(); it runs fine with it uncommented it crashes upon hit.
Why does this crash is this not the proper way to do this? Do I need to somehow detect hit's at the same time? How can the array be at negative 1 when clearly there are still enemies on the screen?
EmmaIterator.remove();
}
}
Though this is not the way I will have things setup this code still should run with no issues. I encounter the same problem when instead of detecting the player enemies collisions I have 2 guns checking for collisions. This seems like a big problem to me which is why I'd say I'm just doing it wrong but documentation is light so I come here.
}
}
#Override
public void resize(int width, int height) {
}
#Override
public void show() {
// start the playback of the background music
// when the screen is shown
//rainMusic.play();
}
#Override
public void hide() {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
FleetTexture.dispose();
PlayerTexture.dispose();
ShootingTexture.dispose();
// dropSound.dispose();
// rainMusic.dispose();
}
}
It's unlikely, unless multithreading is being used, that anything will happen at the same time exactly. You have a number of probable typos in your code, but one will break it:
Rectangle var1_holder = iter.next();
That same reference to iter is in both the first block, which should use it, and the second block, which should use iter1. You should consider using matching variable names, like
Iterator<Rectangle> iter3 = var3.iterator();
if you must have numbers as the only distinguishing feature.
notostraca is right. But to make it more clear i will show u an example with for loops which i use for collisions. it can't make any harm and i hope it will make it more clear for u
int v2 = var2.size();
for (int i = 0; i < v2; i++) {
if (object.getBounds().overlaps(var2.get(i).getBounds())) {
var2.remove(i);
v2--;
//in this line u might use break; if u know that just one object
//from var2 array can hit at a time
}
}
I am developing a game in which I have one player moving on the screen by using on screen analog control.
Enemy sprites are getting added in the scene periodically and they move towards player. By using below code enemies are getting added.
public void addTarget() {
Random rand = new Random();
float x = ( camera.getWidth() + resourcesManager.evilone_region.getWidth());
float minY = resourcesManager.evilone_region.getHeight();
int maxY = (int) (camera.getHeight() - resourcesManager.evilone_region
.getHeight());
int rangeY = (int) (maxY - minY);
float y = rand.nextInt(rangeY) + minY;
target = new AnimatedSprite(x, y, resourcesManager.evilone_region.deepCopy(),vbom){
#Override
protected void preDraw(GLState pGLState, Camera pCamera)
{
super.preDraw(pGLState, pCamera);
pGLState.enableDither();
}
#Override
protected void onManagedUpdate(float pSecondsElapsed)
{
super.onManagedUpdate(pSecondsElapsed);
if(isPlayerMoved){
this.registerEntityModifier(new MoveModifier(2, target.getX(),player.getX(),target.getY(),player.getY()));
}
}
};
attachChild(target);
target.setCullingEnabled(true);
final long[] PLAYER_ANIMATE = new long[] {100, 100, 100};
target.animate(PLAYER_ANIMATE, 0, 2, true);
int minDuration = 2;
int maxDuration = 4;
int rangeDuration = maxDuration - minDuration;
int actualDuration = rand.nextInt(rangeDuration) + minDuration;
mod = new MoveModifier(actualDuration, target.getX(),player.getX(),target.getY(),player.getY());
target.registerEntityModifier(mod.deepCopy());
TargetsToBeAdded.add(target);
}
private void createSpriteSpawnTimeHandler() {
float mEffectSpawnDelay = 1f;
eviloneTimerHandler = new TimerHandler(mEffectSpawnDelay, true,
new ITimerCallback() {
#Override
public void onTimePassed(TimerHandler pTimerHandler) {
if(isPaused){
}else{
//resourcesManager.targetbird.play();
addTarget();
}
}
});
engine.registerUpdateHandler(eviloneTimerHandler);
}
Now the problem is when I move the player with analog control I want result as every enemy should change the direction and move towards player. But by using this code every enemy is moving towards first added enemy and they all move towards player which looks very weird as all of them collapses on each other.
Please help.
You don't have directly move your enemies to player. You can move them 5 pixels every update or something like that. Here is an example but this code must be improved:
#Override
protected void onManagedUpdate(float pSecondsElapsed)
{
super.onManagedUpdate(pSecondsElapsed);
if( player.getX() > target.getX() )
{
//Move your enemy 5 pixels to right
}
else
//Move your enemy 5 pixels to left
if( player.getY() > target.getY() )
{
//Move your enemy 5 pixels to down
}
else
//Move your enemy 5 pixels to up
}
Note: Dont forget to check if target reached player. And before start moving your target check if it is currently moving. You can use a boolean to chechk it. Hope it helps.
I am new to android and building an app which involves displaying a view for 2 seconds and then change. Here's my onDraw method:
#Override
public void onDraw(Canvas canvas)
{
float level = game.level;
width = getWidth();
tile_length = width/level;
Paint rect = new Paint();
rect.setColor(getResources().getColor(R.color.dark));
canvas.drawRect(0, 0, width, width, rect);
game.numbers.setTextSize( (0.70f * tile_length));
game.numbers.setTextAlign(Paint.Align.CENTER);
grid.setColor(getResources().getColor(R.color.lines));
rect.setColor(getResources().getColor(R.color.tile_on));
int ind = 1;
int tile_num = 1;
FontMetrics fm = game.numbers.getFontMetrics();
float x = tile_length/2;
float y = tile_length/2 - (fm.ascent + fm.descent) / 2;
Log.v(LOG_TAG, "changed = " + game.changed);
for (int i=0; i<width; i+=tile_length)
{
for(int j=0; j<width; j+=tile_length)
{
for(int k = 0; k<level; k++ )
if(tile_num == game.random[k])
{
// Log.v(LOG_TAG, "i = " + i + "j = " + j);
game.set_Coordinates(ind-1, i, j);
String tile = Integer.toString(ind++);
canvas.drawRect(i, j, i+tile_length, j+tile_length, rect);
canvas.drawText(tile, i+x, j+y, game.numbers); //needs to be updated after 2 seconds
break;
}
tile_num++;
}
}
}
I understand i have to use postdelayed method somewhere, but don't know how...Now i just want to ommit the canvas.drawText line after the delay.
do you mean something like this
new Handler().postDelayed(new Runnable(){
public void run(){
// do something here like draw text;
}
}, 2000);
A timer is needed, indeed. What I do, which is very simple, is first to create records of coordinates (and any other data needed) for every point of the drawing -- instead of drawing the points on the spot -- and then reproduce them using a timer (Android handler, preferably, like the one suggested above). This also offers you a lot of possibilities while actual drawing: pause, go faster/slower, go backwards, ...
I don't know if this method can be used for complicated drawings, but it is fine for drawing shapes, curves, surfaces, etc.
In my Android app, I am trying to show letters one by one with a short delay between each, while also playing a sound for each letter. I have everything working, and the sounds play with the correct delay, but the text always prints to the screen far too fast. The canvas seems to be updated even when i am not specifically invalidating the view.
Here is what I have so far - I also tried a variant of this based on the "snake" example and had the same results... any help would be appreciated!
public class SpellingView extends View {
private static final String WORD = "TRUCK";
int width;
int height;
String textToPrint;
float textspace;
int j=0;
private final Path arc;
private final Paint tPaint;
//constructor for SpellingView
public SpellingView(Context context) {
super(context);
arc = new Path();
tPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
displayLetterLoop();
}
public void displayLetterLoop(){
for (int i = 0; i < WORD.length(); i++){
final Runnable mUpdateUITimerTask = new Runnable() {
public void run() {
Spelling.mp.start();
}
};
final Handler mHandler = new Handler();
mHandler.postDelayed(mUpdateUITimerTask, i*1500);
}
}
#Override
protected void onDraw(Canvas canvas) {
int k;
// Drawing commands go here
width = canvas.getWidth();
height = canvas.getHeight();
arc.addArc(new RectF((width*.15f), (height*.15f), (width*.85f), (height*.4f)), 180,180);
tPaint.setStyle(Paint.Style.FILL_AND_STROKE);
tPaint.setColor(Color.RED);
tPaint.setTextSize(height * 0.1f);
tPaint.setTextAlign(Paint.Align.LEFT);
setBackgroundColor(Color.BLACK);
for (k = 0; k < j; k++){
char c = WORD.charAt(k);
String cs = Character.toString(c);
textToPrint+= cs;
textspace =(float) (k*(width/WORD.length())*.9);
canvas.drawTextOnPath(cs, arc, textspace , 0, tPaint);
}
if(j<WORD.length()){
j++;
}
}
}
Custom view will invalidate itself when is a part of a layout which for some reason redraw itself. Therefore you could envelop your code in onDraw() with a condition and a flag so that it draws your stuff only when the timer sets the flag and calls invalidate. After one letter is drawn then the flag shoud be set on false like:
if (drawLetter){
drawLetter = false;
/code...
}
However this also may need to be a sychronized block.
OnDraw should happen 60 times a second and not only when you are invalidating.
So maybe you need to update some class variables (when you are invalidating) and use those for your draw logic # OnDraw.