I am building an Android game where a ball is controlled and moved using the motion sensor.
There are some posts on how to draw an inverted circle like this one, but it is unusable as Android does not support BufferedImage.
I created the player using the codes below
public class Player extends Task {
private final static float MAX_SPEED = 20;
private final static float SIZE = 16;
private Circle _cir = null;
private Paint _paint = new Paint();
private Vec _vec = new Vec();
private Vec _sensorVec = new Vec();
public Player(){
_cir = new Circle( 15, 15, SIZE ); //15,15 is the initial x,y coordinates
}
public final Circle getPt(){
return _cir;
}
private void setVec(){
float x = -AcSensor.Inst().getX()*2;
float y = AcSensor.Inst().getY()*2;
_sensorVec._x = x < 0 ? -x*x : x*x;
_sensorVec._y = y < 0 ? -y*y : y*y;
_sensorVec.setLengthCap(MAX_SPEED);
_vec.blend( _sensorVec, 0.05f );
}
private void Move(){
_cir._x += _vec._x;
_cir._y += _vec._y;
}
#Override
public boolean onUpdate(){
setVec();
Move();
return true;
}
#Override
public void onDraw( Canvas c ){
c.drawCircle(_cir._x, _cir._y, _cir._r, _paint);
}
}
Question is, how to create an inverted circle around the player so that the player only sees a limited distance while the outer part is filled with black color? For example, something like this:
.
Related
I would like to make something like this
for Android 5.0 and above?
How can I implement this? I can not found any solution on StackOverFlow or on android developer site.
I suggested that I can make status bar transparent and draw gradient drawable under status bar. But there are few problems.
First problem is that usual gradient from shape drawable doesn't support Material Design spec http://www.google.com/design/spec/style/imagery.html
Second problem is that I can not fit map fragment to windows via android:fitsSystemWindows="true".
Formula that gives approximately same plot as shown on the site of Material Design is:
y = 3/(4*(x+0.5)) - 0.5
I've tried several ways to draw hyperboloid gradient via Canvas and found the fastest solution.
public class HyperbolaGradientDrawable extends Drawable {
private static final int ALPHA_DEFAULT = (int) (0.6f * 255);
private int mAlpha = ALPHA_DEFAULT;
private int mColor;
private Rect mBmpRect = new Rect();
private int[] mColors = new int[0];
private Bitmap mBmp;
#Override
public void draw(Canvas canvas) {
Rect bounds = getBounds();
if (mColors.length != bounds.height()) {
int alpha;
float y, alphaRelative;
mColors = new int[bounds.height()];
for (int i = 0; i < bounds.height(); i++) {
y = ((float) i) / bounds.height();
// this function gives approximately 0.5 of the bearing alpha at 3/10ths closed to the darker end
alphaRelative = 3 / (4 * (y + 0.5f)) - 0.5f;
alpha = (int) (alphaRelative * mAlpha);
mColors[i] = alpha << 24 | mColor;
}
mBmp = Bitmap.createBitmap(mColors, 1, bounds.height(), Bitmap.Config.ARGB_8888);
mBmpRect.set(0, 0, 1, bounds.height());
}
canvas.drawBitmap(mBmp, mBmpRect, bounds, null);
}
public void setColor(int color) {
// remove alpha chanel
mColor = color & 0x00FFFFFF;
}
#Override
public void setAlpha(int alpha) {
mAlpha = alpha;
}
#Override
public void setColorFilter(ColorFilter colorFilter) {
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
I know that Google recommend to do not create new objects in draw method, but it works faster than drawing line by line through Canvas.
You can look at comparison of several ways in demo project
So I am using the libgdx framework and am new to android games development. I have an array of yellow circle objects stored in each index which are shown on the game screen when I run them, all the circle objects are in different x positions but on the same y axis. I want to basically set the visibility of each circle for a given amount of time before the next one becomes visible for say 1000 ms per circle. So for example circle 1 will be visible for 1000 ms then it will become invisible and circle 2 will then become visible for 1000ms so on and so forth, till I reach the end of the list.
public class Spot {
private float x;
private float y;
private float radius;
private Circle spot;
private Circle spotList[];
public Spot(float x, float y, float radius, int amount){
this.x = x;
this.y = y;
this.radius = radius;
spot = new Circle(x,y,radius);
spotList = new Circle[amount];
for(int i = 0; i < spotList.length; i++){
spotList[i] = new Circle(this.x+(i*15), this.y, this.radius);
}
}
public void update(float delta){
}
public Float getX(){
return x;
}
public Float getY(){
return y;
}
public float getRadius(){
return radius;
}
public Circle[] getSpots(){
return spotList;
}
public Circle getSpot(){
return spot;
}
}
The rendering of the shape has been outsourced to a different class I want to be able to handle the visibility of the circles etc in the update method.
Since you're not using Actors (https://github.com/libgdx/libgdx/wiki/Scene2d), you need to keep track of time yourself and make the circles visible/not visible.
You will want to add
private float elapsedTime = 0.0f;
private float currentCircle = 0;
two fields, one for keeping track of elapsed time and one for the currently visible circle.
public void update(float delta){
elapsedTime += delta;
if (elapsedTime >= 1.0f) { // more than one second passed
spot[currentCircle].setVisible(false);
if (currentCircle + 1 < spotList.size()) {
currentCircle++;
spot[currentCircle].setVisible(true);
elapsedTime -= 1.0f; // reset timer (don't just set to 0.0f to avoid time shifts)
}
}
}
In the update method, count elapsedTime and if more then one seconds passed, make old circle not visible and new circle visible. Also make sure that initially the first circle is visible and that the timer is 0.
A possible solution is to use the Universal Tween Engine which works well with the libGDX framework. Visit the link to see how to include it in your project and for documentation.
As a quick demonstration on how to use it:-
Create and instantiate a TweenManager and your array of Spots in your class responsible for rendering.
protected TweenManager tweenManager = new TweenManager();
Spot spots[] = new Spot[...];
...
Create your timer by implementing the TweenCallback()
final int numberOfSpots = 5;
int spotArrayIndex = 0;
float timeDelay = 1000f; /*1000 milliseconds*/
Tween.call(new TweenCallback() {
#Override
public void onEvent(int type, BaseTween<?> source) {
/*set or unset the visibility of your Spot objects here i.e. */
spots[spotArrayIndex++].setVisible(false); /*Set current spot invisible*/
spots[spotArrayIndex].setVisible(true); /*Set next spot to be visible*/
}
}).repeat(numberOfSpots, timeDelay).start(tweenManager);
Update the tweenManager in your render method
public void render(float delta) {
...
tweenManger.update(delta);
...
}
Please check the code for errors if you use it, as I am not sure of the rest of your code.
I'm making a game with Andengine and i'm stuck for 2 days on shooting from a rotating sprite. I'm not a hero at geometry and already ask a teacher but he could also not provide me the correct answer. So who is a mathematics hero and help me out :).
The problem is that i cannot figure out where the bullet has to spawn in front of the turret. Rotating and finding the destination where the bullet has to go is no problem. It only about the spawn point.
I removed a lot of not-interesting-code for this question.
Okay so here is the rotating code from the turret-rotation:
public class AlienShip extends Ship {
public static final float BASE_ROTATION_SPEED = 0.25f;
public static final int DEFAULT_IMAGE_ROTATION = 90; //90 degrees
protected PlayerShip ship;
public AlienShip(float pX, float pY, TextureRegion pTextureRegion,
VertexBufferObjectManager pVertexBufferObject,FixedStepPhysicsWorld pw, int baseDurability) {
super(pX, pY, pTextureRegion, pVertexBufferObject, pw, baseDurability);
}
public void rotateToPlayer()
{
if (ship != null) {
float dX = this.getX() - ship.getX();
float dY = this.getY() - ship.getY();
float angle = (float) Math.atan2(-dY, dX);
float rotation = MathUtils.radToDeg(angle) + DEFAULT_IMAGE_ROTATION;
RotationModifier rotMod = new RotationModifier(BASE_ROTATION_SPEED, this.getRotation(), rotation);
this.registerEntityModifier(rotMod);
}
}
public void rotateToInitPos() {
RotationModifier rotMod = new RotationModifier(BASE_ROTATION_SPEED, this.getRotation(), 0);
this.registerEntityModifier(rotMod);
}
}
The code above is working fine.
Here is the code from the laser that the ship is shooting.
Read the comments to find out witch part is not working.
public class GameScene extends Scene {
protected PlayerShip playerShip;
private SpawnCallback createShootCallback(boolean player) {
return new SpawnCallback() {
#Override
public void spawn(SpawnTimer spawnTimer) {
PhysicsSprite laser = null;
AlienShip alienShip = (AlienShip) spawnTimer.getPhysicsSprite();
// laser = alienMissilePool.getMissileFromPool(x,y)
//spawn the laser in front of the rotating ship [Not working :( ]
laser = alienMissilePool.getMissileFromPool( ( alienShip.getX() * FloatMath.cos(MathUtils.degToRad(rotation)) - ((1280 - alienShip.getY() - alienShip.getY()/2) * FloatMath.sin(MathUtils.degToRad(rotation)) ) ) ,
( alienShip.getX() * FloatMath.sin(MathUtils.degToRad(rotation)) + ((1280 - alienShip.getY() - alienShip.getY()/2) * FloatMath.cos(MathUtils.degToRad(rotation)) ) ) );
//Set the rotation from the laser same to the ship rotation [Is working perfectly].
float rotation = alienShip.getRotation();
laser.setRotation(rotation);
//Set laser speed and direction [Is working perfectly]
float pX = 0.01f * (playerShip.getX() - laser.getX());
float pY = 0.01f * (playerShip.getY() - laser.getY());
laser.getSpriteBody().setLinearVelocity(pX, pY);
spawnPhysicsSprite(laser);
}
};
}
}
Here is a link to a drawing that shows the x-axis and y-axis values.
http://s24.postimg.org/citz29339/gamescene.png
Thank you!
Instead of getting into maths, why don't you put an object (Entity) positioned on the place of the turret and use it's position as the spawn point for the laser ?
so your turret would have an Entity attached to it on the place of the gun.
tell me if you need an example code
UPDATE Looks like this is a problem because of the static notification bar on tablet because of the lack of hardware buttons. I just didn't think about that. Anyway, in the case of the TF101 it returns a resolution of 1280x752 so about 1.702 (80 : 47) ratio. If I use a suitable unit size, like 33.5 or 11.75 vertically I get the proper scaling and this seems to fix the problem of skewed pixels.
END UPDATE
I've been setting up a game using 16x16 units for my tiled maps. I am using the resolution 1280x800 on both my desktop and android projects, I'm testing this to get a sense of how it will look on my TF101 asus tablet. I currently use a camera with units of 20x12.5 (wxh) and notice no pixel scaling on my desktop project, but when I run the game on my android I get weird scaling, and a green horizontal line. I can also move about quarter cell further along the x-axis on the tablet, shown in the screen shots. The pixels on the android project don't seem uniform at all.
I set the verticalTiles amount to 12.5f, then calculate the horizontalTiles amount as
verticalTiles = 12.5f;
...
horizontalTiles = (float) width / (float) height * verticalTiles;
camera = new OrthographicCamera(horizontalTiles, verticalTiles);
I'm aiming for devices with different aspect ratios to simply see more or less of the map, but can't seem to get working correctly. Any help would be appreciated.
Android Capture - http://imageshack.us/f/7/dsvg.png/ - notice the highlights on the roof edges, they are not uniform at all.
Desktop Capture - http://imageshack.us/f/853/5itv.png/
Current MainGame class
package com.bitknight.bqex;
/* Bunch of imports */
public class MainGame implements ApplicationListener {
private OrthographicCamera camera;
private SpriteBatch spriteBatch;
private TiledMap map;
private OrthogonalTiledMapRenderer mapRenderer;
private Texture texture;
private Texture clothArmor;
private Sprite sprite;
private BitmapFont font;
private float horizontalTiles = 0;
private float verticalTiles = 12.5f;
private int hoverTileX = 0;
private int hoverTileY = 0;
private TiledMapTileLayer layer;
private Cell cell;
private TiledMapTile canMoveToTile;
private TiledMapTile cannotMoveToTile;
private AnimatedTiledMapTile animatedStopTile;
private AnimatedTiledMapTile animatedGoTile;
private Texture spriteSheet;
private TextureRegion region;
private Player player;
float h, w;
float ppuX, ppuY;
#Override
public void create() {
// Setup the animated tiles
Array<StaticTiledMapTile> tileArray;
// Start position on the sheet
int startX = 192;
int startY = 1568;
spriteSheet = new Texture(Gdx.files.internal("data/maps/tilesheet.png"));
spriteSheet.setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
// We are trying to load two strips of 4 frames, 8 total
for( int i = 0; i < 2; ++i ) {
tileArray = new Array<StaticTiledMapTile>(4);
for( int j = 0; j < 4; ++j ) {
region = new TextureRegion(spriteSheet, startX, startY, 16, 16);
tileArray.add(new StaticTiledMapTile(region));
startX += 16;
}
if( i == 0 ) {
animatedStopTile = new AnimatedTiledMapTile(1/10f, tileArray);
} else {
animatedGoTile = new AnimatedTiledMapTile(1/10f, tileArray);
}
}
// Load the map
map = new TmxMapLoader().load("data/maps/base.tmx");
// Setup the two tiles that show movable and not movable sprites
canMoveToTile = map.getTileSets().getTileSet(0).getTile(1959);
canMoveToTile.setBlendMode(BlendMode.ALPHA);
cannotMoveToTile = map.getTileSets().getTileSet(0).getTile(1958);
cannotMoveToTile.setBlendMode(BlendMode.ALPHA);
// Manually create the layer used to show the cursor sprites
layer = new TiledMapTileLayer(100, 100, 16, 16);
layer.setName("display");
cell = new Cell();
cell.setTile(canMoveToTile);
layer.setOpacity(1f);
mapRenderer = new OrthogonalTiledMapRenderer(map, 1/16f);
spriteBatch = new SpriteBatch();
font = new BitmapFont(Gdx.files.internal("data/consolas.fnt"), false);
font.setScale(0.6f);
texture = new Texture(Gdx.files.internal("data/maps/tilesheet.png"));
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
clothArmor = new Texture(Gdx.files.internal("data/img/native/clotharmor.png"));
region = new TextureRegion(clothArmor, 32, 256, 32, 32);
sprite = new Sprite(region);
sprite.setOrigin(0.5f, 0.5f);
sprite.setPosition(0f - 0.5f, 0f);
sprite.setSize(2, 2);
// Setup player and associated animations
Array<TextureRegion> regions = new Array<TextureRegion>();
player = new Player();
}
#Override
public void dispose() {
spriteBatch.dispose();
texture.dispose();
clothArmor.dispose();
spriteSheet.dispose();
}
#Override
public void render() {
player.update(Gdx.graphics.getDeltaTime());
camera.update();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if( Gdx.input.isKeyPressed(Input.Keys.ESCAPE) ) {
Gdx.app.exit();
}
// Clear the last cell
layer.setCell(hoverTileX, hoverTileY, null);
// Convert screen coordinates to world coordinates
Vector3 worldCoordinates = new Vector3(Gdx.input.getX(0), Gdx.input.getY(0), 0);
camera.unproject(worldCoordinates);
hoverTileX = (int)(worldCoordinates.x);
hoverTileY = (int)(worldCoordinates.y);
TiledMapTileLayer layer = (TiledMapTileLayer)map.getLayers().get("collision");
if( Gdx.input.isTouched(0) ) {
//sprite.setPosition(hoverTileX - 0.5f, hoverTileY);
player.pos.x = hoverTileX - 0.5f;
player.pos.y = hoverTileY - 0.25f;
cell.setTile(animatedGoTile);
} else {
if (layer.getCell(hoverTileX, hoverTileY) != null) {
cell.setTile(cannotMoveToTile);
} else {
cell.setTile(canMoveToTile);
}
}
layer.setCell(hoverTileX, hoverTileY, cell);
mapRenderer.setView(camera);
mapRenderer.render();
mapRenderer.getSpriteBatch().begin();
mapRenderer.renderTileLayer(layer);
mapRenderer.getSpriteBatch().end();
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.begin();
player.render(spriteBatch);
spriteBatch.end();
}
#Override
public void resize(int width, int height) {
horizontalTiles = (float) width / (float) height * verticalTiles;
camera = new OrthographicCamera(horizontalTiles, verticalTiles);
w = width;
h = height;
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
Looks like this is a problem because of the static notification bar on tablet because of the lack of hardware buttons. I just didn't think about that. Anyway, in the case of the TF101 it returns a resolution of 1280x752 so about 1.702 (80 : 47) ratio. If I use a suitable unit size, like 33.5 or 11.75 vertically I get the proper scaling and this seems to fix the problem of skewed pixels.
Also, while this is good for the TF101 tablet in my case it's not really a great solution. Here is a Gemserk series that talks about a nice solution.
http://blog.gemserk.com/2013/01/22/our-solution-to-handle-multiple-screen-sizes-in-android-part-one/
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.