android画布油漆圈与辉光动画

时间:2015-09-12 13:14:31

标签: java android canvas

我想制作一个圆圈(称为核心)发光,其动画效果就像从明亮变为低光。当我使用paint.setShadow方法时,我画布上的所有东西都会发光,而不仅仅是核心圆。我怎样才能将它应用到核心?



package com.mickvdijke.circles;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.*;

import android.graphics.*;
import android.graphics.drawable.*;
import android.util.Log;
import android.content.res.*;
import android.content.*;
import android.app.*;

import com.mickvdijke.circles.framework.Game;
import com.mickvdijke.circles.framework.Screen;


public class GameScreen extends Screen {
    long startTime = System.nanoTime();
	World world;

	Paint paint = new Paint();
	RectF rect = new RectF();

	GradientDrawable gradient;

	Context r;
        
    public GameScreen(Game game) {
        super(game);
		r = (Context) game;
		world = new World(game);	
		world.renew();
		rect.top = world.core.coords.y - world.core.shieldRadius;
		rect.left = world.core.coords.x - world.core.shieldRadius;
		rect.bottom = world.core.coords.y + world.core.shieldRadius;
		rect.right = world.core.coords.x + world.core.shieldRadius;

		paint.setAntiAlias(true);
		paint.setStrokeWidth(0.0F);
		
		// This gradient looks quite smooth, but not perfect
		gradient = new GradientDrawable(GradientDrawable.Orientation.TL_BR,
				new int[]{0xff001319, 0xff013e3f});
		gradient.setGradientType(GradientDrawable.RADIAL_GRADIENT);
		gradient.setGradientRadius((int) world.offScreenRadius);
		gradient.setDither(false);
		gradient.setGradientCenter(0.5F, 0.5F);
		gradient.setBounds(new Rect(0, 0, game.getGraphics().getWidth(),
				   	game.getGraphics().getHeight()));
		
		paint.setTextSize(((float)game.getGraphics().getHeight()) / 16F);
		paint.setTextAlign(Paint.Align.CENTER);
    }
    
    @Override
    public void update(float deltaTime) {
		world.update(deltaTime);
    }

    @Override
    public void present(float deltaTime) {
    Canvas c = game.getGraphics().getCanvas();    
	gradient.draw(c);
	paint.setStyle(Paint.Style.FILL_AND_STROKE);
	if(world.core.shieldEnergy > 0.0F)
	{
		paint.setColor(0xff003cca);
		paint.setAlpha((int) (80.0F +
				   	(255.0F - 80.0F) * world.core.shieldEnergy));
		c.drawCircle(world.core.coords.x, world.core.coords.y,
			world.core.shieldRadius, paint);
		paint.setAlpha(255);
	}
	paint.setColor(0xffea2533);
    paint.setShadowLayer(30, 0, 0, Color.RED);
        c.drawCircle(world.core.coords.x, world.core.coords.y,
                world.core.maxRadius * world.core.health,
                paint);
	paint.setStyle(Paint.Style.STROKE);
	paint.setColor(0xffffffff);
	paint.setStrokeWidth(Core.SHIELD_WIDTH);
	c.drawArc(rect, (360.0F - world.core.angle),
			(360.0F - world.core.GAP_ANGLE), false, paint);
	paint.setStrokeWidth(0.0F);
	paint.setStyle(Paint.Style.FILL_AND_STROKE);
	Iterator<Dot> iterator = world.dots.iterator();
	while(iterator.hasNext())
	{
		int color = 0;
		Dot dot = iterator.next();
		if(dot.type == Dot.Type.Enemy)
			color = 0xffe2192e;
		else if(dot.type == Dot.Type.Health)
			color = 0xff19dbe2;
		else if(dot.type == Dot.Type.Shield)
			color = 0xff003cca;
		paint.setColor(color);
		c.drawCircle(dot.coords.x, dot.coords.y,
				dot.maxRadius * dot.energy, paint);
    }

	if(world.state == World.GameState.Running)
		drawMessage(world.getTime(), c);
	else if(world.state == World.GameState.Ready)
		drawMessage(r.getString(R.string.ready), c);
	else if(world.state == World.GameState.Paused)
		drawMessage(r.getString(R.string.paused), c);
	else if(world.state == World.GameState.GameOver)
		drawMessage(r.getString(R.string.game_over)+
				"\n"+
				r.getString(R.string.your_time) +  " " + world.getTime() +
				"\n\n" + r.getString(R.string.game_url), c);
	}

	private void drawMessage(String message, Canvas c)
	{
		float y = paint.getTextSize();
		for(String line: message.split("\n"))
		{
		// Draw black stroke
		paint.setStrokeWidth(2F);
		paint.setColor(0xff000000);
	    paint.setStyle(Paint.Style.STROKE);

		c.drawText(line, c.getWidth()/2F, y, paint);
		// Draw white text
		paint.setStrokeWidth(0.0F);
		paint.setColor(0xffffffff);
	    paint.setStyle(Paint.Style.FILL);

		c.drawText(line, c.getWidth()/2F, y, paint);

		y += paint.getTextSize();
		}
	}

    @Override
    public void pause() {
		world.state = World.GameState.Paused;
    }

    @Override
    public void resume() {
    }

    @Override
    public void dispose() {
    }            
}
&#13;
&#13;
&#13;

&#13;
&#13;
package com.mickvdijke.circles;

import java.util.*;


import android.util.*;

import com.mickvdijke.circles.framework.Audio;
import com.mickvdijke.circles.framework.Game;
import com.mickvdijke.circles.framework.Graphics;
import com.mickvdijke.circles.framework.Input;
import com.mickvdijke.circles.framework.Sound;

/* I should have used pools for my objects not to make garbage
 * collector angry. As it freezes the game sometimes, 
 * I avoided some object creations. However, it doesn't help.
 */

public class World
{
	Random random = new Random();
	Game game;
	private final int DOTS_COUNT = 10;
	// In this case ArrayList is better than LinkedList:
	// list will never be resized.
	public List<Dot> dots = new ArrayList<Dot>(DOTS_COUNT);
	public Core core = new Core();
	public float offScreenRadius;
	private final float SHIELD_FACTOR = 20.0F;
	private final float ENERGY_FACTOR = 6.0F;

	private float time = 0.0F; // in seconds

	public enum GameState {Ready, Running, Paused, GameOver}

	public GameState state = GameState.Ready;

	private float difficulty = 0.04F; // Max 0.1F

	// Sounds
	// Dot collides with core
	Sound coreHurt;
	Sound coreHealth;
	Sound coreShield;
	// Dot collides with shield
	Sound shieldCollision;

	Sound gameOver;

	public World(Game game)
	{
		this.game = game;
		Graphics g = game.getGraphics();
		// Construct core
		core.coords = new VectorF((float) g.getWidth() / 2,
			   	(float) g.getHeight() / 2);
		core.shieldRadius = (float) g.getWidth() / 4;
		core.maxRadius = core.shieldRadius * 0.7F;
		core.angle = 0.0F;
		core.health = 1.0F;
		core.shieldEnergy = 0.0F;
		// Set offScreenRadius
		offScreenRadius = (float) Math.hypot((double) g.getWidth() / 2,
				(double) g.getHeight() / 2);
		// Max dot radius (when it's energy is 1.0F)
		Dot.maxRadius = core.maxRadius / 8.0F;
		loadSounds();
	}

	private void loadSounds()
	{
		Audio a = game.getAudio();
		coreHurt = a.newSound("core_hurt.wav");
		coreHealth = a.newSound("core_health.wav");
		coreShield = a.newSound("core_shield.wav");
		shieldCollision = a.newSound("shield_collision.wav");
		gameOver = a.newSound("game_over.wav");
	}

	// Restart the game	
	public void renew()
	{
		dots.clear();
		core.health = 1.0F;
		core.shieldEnergy = 0.0F;
		time = 0.0F;
		state = GameState.Ready;
		difficulty = 0.04F;
		generateStartDots(DOTS_COUNT);
	}
	// Add randomness
	private void generateStartDots(int count)
	{
		for(int i = 0; i < count; i++)
		{
			generateNewDot(true);
		}
	}

	private VectorF generateNewDotCoordsInRandomPlace()
	{
		double angle = random.nextDouble() * 2 * Math.PI;
		VectorF coords = new VectorF((float) Math.cos(angle), 
				(float) Math.sin(angle));
		coords = coords.multiply(core.shieldRadius + (offScreenRadius -
					core.shieldRadius) * random.nextFloat());
		return coords;
	}

	public void update(float deltaTime)
	{
		if(state == GameState.Ready)
			updateReady(deltaTime);
		if(state == GameState.Running)
			updateRunning(deltaTime);
		if(state == GameState.Paused)
			updatePaused(deltaTime);
		if(state == GameState.GameOver)
			updateGameOver(deltaTime);
	}

	private void doInput()
	{
	    float orientAngle = game.getInput().getAzimuth();
		if(game.getInput().isTouchDown())
		{
			double touchX = (double) game.getInput().getTouchX();
			double touchY = (double) game.getInput().getTouchY();
			core.angle = 
				// Y-axis is inverted. See checkCollisionWithShield(...)
				// method
				normAngle(((float) (Math.atan2(-(touchY - core.coords.y), 
						touchX - core.coords.x) / (Math.PI * 2) *
				360.0)) - Core.GAP_ANGLE/2F);
		}
		else
		{
			core.angle = stabilizeAngle(orientAngle - Core.GAP_ANGLE/2F,
					core.angle, 8F);
		}
	}

	// Removes accelerometer noise and makes
	// core shield rotate smooth when user touches / untouches
	// the screen (and game switch accelerometer / touchscreen control).
	// Stabilisation increases, as factor value becomes larger.
	private float stabilizeAngle(float real, float current, float factor)
	{
		real = normAngle(real);
		current = normAngle(current);
		// Stabilisation should choose shortest way
		// (is it better to rotate clockwise or counterclockwise?)
		if(current - real > 180F)
			real += 360;
		if(real - current > 180F)
			real -= 360;
		// (current + current + current ... + real) / numberOfElements
		return normAngle((current * factor + real) / (factor + 1F));
	}

	private void updateReady(float deltaTime)
	{
		if(checkTouchUp() || checkMenuUp())
			state = GameState.Running;
	}
	
	private boolean checkTouchUp()
	{
		for(Input.TouchEvent event : game.getInput().getTouchEvents())
		{
			if(event.type == Input.TouchEvent.TOUCH_UP)
				return true;
		}
		return false;
	}

	private boolean checkMenuUp()
	{
		for(Input.KeyEvent event : game.getInput().getKeyEvents())
		{
			if(event.keyCode == android.view.KeyEvent.KEYCODE_MENU)
			{
				if(event.type == Input.KeyEvent.KEY_UP)
					return true;
			}

		}
		return false;
	}

	private void updatePaused(float deltaTime)
	{
		if(checkTouchUp() || checkMenuUp())
			state = GameState.Running;
	}

	private void updateGameOver(float deltaTime)
	{
		if(checkTouchUp() || checkMenuUp())
			renew();
	}

	private void updateRunning(float deltaTime)
	{
		checkTouchUp(); // Just to clear touch event buffer

		if(checkMenuUp())
			state = GameState.Paused;

		countTime(deltaTime);

		doInput();

		generateNewDots(DOTS_COUNT);

		handleCollisions();
		moveDots(deltaTime);
		decreaseShieldEnergy(deltaTime);
	}

	private void decreaseShieldEnergy(float deltaTime)
	{
		if(core.shieldEnergy > 0.0F)
		{
			core.shieldEnergy -= deltaTime / SHIELD_FACTOR;
			if(core.shieldEnergy < 0.0F)
			core.shieldEnergy = 0.0F;
		}
	}

	private void generateNewDots(int neededCount)
	{
		float rand = random.nextFloat();
		if(neededCount > dots.size())
			generateNewDot(false);
	}

	private void increaseDifficulty()
	{
		difficulty += 0.00005F;
	}

	private void generateNewDot(boolean atStart)
	{
		float linearSpeed = 10.0F * difficulty;
		Dot dot = new Dot();
		if(atStart)
		{
			dot.coords = generateNewDotCoordsInRandomPlace();
		}
		else
		{
			dot.coords = generateNewDotAtOffScreenRadius();
			increaseDifficulty();
		}
		VectorF speed = new VectorF(
				linearSpeed * (-dot.coords.x / dot.coords.length()),
			   linearSpeed * (-dot.coords.y / dot.coords.length()));
		dot.speed = speed;
		dot.coords.addToThis(core.coords);
		dot.energy = random.nextFloat();
		if(dot.energy <= 0.3F)
			dot.energy = 0.3F;
		float typeRand = random.nextFloat();
		Dot.Type type;
		if (typeRand >= 0.9)
			type = Dot.Type.Shield;
		else if (typeRand >= 0.8)
			type = Dot.Type.Health;
		else
			type = Dot.Type.Enemy;
		dot.type = type;
		dots.add(dot);
	}

	private void countTime(float deltaTime)
	{
		time += deltaTime;
	}

	public String getTime()
	{
		int seconds = (int) time;
		int minutes = seconds / 60;
		seconds %= 60;
		String result = "";
		if(minutes > 0)
			result += minutes + ":";
		result += String.format("%02d", seconds);
		return result;
	}

	private VectorF generateNewDotAtOffScreenRadius()
	{
		float angle = random.nextFloat() * ((float)(2 * Math.PI));
		VectorF coords =
		   	new VectorF(offScreenRadius * ((float) Math.cos(angle)),
					offScreenRadius * ((float) Math.sin(angle)));
		return coords;
	}
	private void moveDots(float deltaTime)
	{
		for(Dot dot : dots)
		{
			dot.coords.addToThis(dot.speed.x * deltaTime * 100.0F,
					dot.speed.y * deltaTime * 100.0F);
		}
	}

	private void handleCollisions()
	{
		Iterator<Dot> iterator = dots.iterator();
		while(iterator.hasNext())
		{
			handleCollision(iterator.next(), iterator);
		}
	}

	private void handleCollision(Dot dot, Iterator<Dot> iterator)
	{
		float lengthToCoreCenter = (float)
			Math.hypot((double)(dot.coords.x - core.coords.x),
					(double)(dot.coords.y - core.coords.y)); 
		if(Math.abs(lengthToCoreCenter - 
					core.shieldRadius) <= dot.maxRadius * dot.energy +
				Core.SHIELD_WIDTH)
			checkCollisionWithShield(dot, iterator);
		else if (lengthToCoreCenter - core.maxRadius * core.health <=
			   	dot.maxRadius * dot.energy)
			handleCollisionWithCore(dot, iterator);
	}

	private void checkCollisionWithShield(Dot dot, Iterator<Dot> iterator)
	{
		// I normalize (move into (0; 360) interval) angles
		// in some places. Don't know if it's needed.
		if(core.shieldEnergy > 0.0F)
		{
			iterator.remove();
			shieldCollision.play(dot.energy);
			game.getVibration().vibrate(30);
		}
		else
		{
		// Pay attention at -v.y! Y-axis is inverted, 
		// because it points downwards.
		float dotAngle = (float) Math.atan2((double) - 
				(dot.coords.y - core.coords.y),
			   	(double) (dot.coords.x - core.coords.x));
		dotAngle = dotAngle / (((float) Math.PI) * 2.0F) * 360.0F;
		dotAngle = normAngle(dotAngle);
		// For example, dotAngle = 3, and core.angle = 365
		// We need to solve this somehow:
		core.angle = normAngle(core.angle);
		while(dotAngle < core.angle)
		{
			dotAngle += 360.0F;
		}
		// OK, and check if dotAngle is within the gap
		if(!((dotAngle > core.angle) &&
				   	(dotAngle < core.angle + core.GAP_ANGLE)))
		{
			iterator.remove();
			shieldCollision.play(dot.energy);
			game.getVibration().vibrate(30);
		}
		}
	}

	private float normAngle(float angle)
	{
		float angle2 = angle;
		while(angle2 < 0.0F)
			angle2 += 360.0F;

		while(angle2 > 360.0F)
			angle2 -= 360.0F;

		return angle2;
	}

	private void handleCollisionWithCore(Dot dot, Iterator<Dot> iterator)
	{
		if(dot.type == Dot.Type.Enemy)
		{
		core.health -= dot.energy / ENERGY_FACTOR;
		if(core.health < 0.0F)
		{
			state = GameState.GameOver;
			gameOver.play(1F);
			game.getVibration().vibrate(10);
			game.getVibration().vibrate(40);
			game.getVibration().vibrate(100);
			core.health = 0.0F;
		}
		coreHurt.play(dot.energy);
		}
		else if (dot.type == Dot.Type.Health)
		{
		core.health += dot.energy / ENERGY_FACTOR;
		if(core.health > 1.0F)	
		{
			core.health = 1.0F;
		}
		coreHealth.play(dot.energy);
		}
		else if(dot.type == Dot.Type.Shield)
		{
			core.shieldEnergy += dot.energy;
			if(core.shieldEnergy > 1.0F)
				core.shieldEnergy = 1.0F;
			coreShield.play(dot.energy);
		}
		iterator.remove();
		game.getVibration().vibrate(30);
	}

}
&#13;
&#13;
&#13;

0 个答案:

没有答案