I am new to android programming and trying to create 5 rectangles(two on the right side of the screen and three on the left side of the screen) on android using the canvas drawRect method, but it only shows the top left rectangle only. What am I doing wrong here? Thanks for your help.
Here's my RectAngle class:
public class RectAngle extends View {
public RectAngle(Context context) {
super(context);
setFocusable(true);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float x = getWidth();
float y = getHeight();
Paint topLeftRect = new Paint();
Paint bottomLeftRect = new Paint();
Paint topRightRect = new Paint();
Paint midRightRect = new Paint();
Paint bottomRightRect = new Paint();
// Draw the top left rectangle
topLeftRect.setStyle(Paint.Style.FILL);
//topLeftRect.setColor(Color.WHITE);
topLeftRect.setColor(Color.parseColor("#FFFF99"));
// canvas.drawPaint(topLeftRect);
canvas.drawRect(0, 0, x / 2, y / 2, topLeftRect);
//Draw the bottom left rectangle
bottomLeftRect.setStyle(Paint.Style.FILL);
//bottomLeftRect.setColor(Color.WHITE);
// canvas.drawPaint(bottomLeftRect);
bottomLeftRect.setColor(Color.parseColor("#FFFF99"));
canvas.drawRect(0, y / 2, x / 2, 0, bottomLeftRect);
//Draw the top tight rectangle
topRightRect.setStyle(Paint.Style.FILL);
//topRightRect.setColor(Color.WHITE);
topRightRect.setColor(Color.parseColor("#FF6600"));
//canvas.drawPaint(topRightRect);
canvas.drawRect(x / 2, 0, 0, y / 3, topRightRect);
// Draw the middle right rectangle
midRightRect.setStyle(Paint.Style.FILL);
//midRightRect.setColor(Color.WHITE);
midRightRect.setColor(Color.parseColor("#66FFFF"));
// canvas.drawPaint(midRightRect);
canvas.drawRect(x / 2, 0, 0, y / 3, midRightRect);
//Draw the bottom right rectangle
bottomRightRect.setStyle(Paint.Style.FILL);
//bottomRightRect.setColor(Color.WHITE);
bottomRightRect.setColor(Color.parseColor("#CCCC00"));
// canvas.drawPaint(bottomRightRect);
canvas.drawRect(x/2, y/3, 0, 0, bottomRightRect);
}
}
Here's my main activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new RectAngle(this));
//setContentView(R.layout.activity_main);
}
Here's an image of my emulator. I am only getting one colored rectangle and it should be 4 more on the bottom left, top right, middle right, and bottom right of the screen.
Emulator image
public class RectAngle extends View {
public RectAngle(Context context) {
super(context);
setFocusable(true);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float x = getWidth();
float y = getHeight();
Paint topLeftRect = new Paint();
Paint bottomLeftRect = new Paint();
Paint topRightRect = new Paint();
Paint midRightRect = new Paint();
Paint bottomRightRect = new Paint();
// Draw the top left rectangle
topLeftRect.setStyle(Paint.Style.FILL);
//topLeftRect.setColor(Color.WHITE);
topLeftRect.setColor(Color.parseColor("#FFFF99"));
// canvas.drawPaint(topLeftRect);
canvas.drawRect(0, 0, x / 2, y / 2, topLeftRect);
//Draw the bottom left rectangle
bottomLeftRect.setStyle(Paint.Style.FILL);
//bottomLeftRect.setColor(Color.WHITE);
// canvas.drawPaint(bottomLeftRect);
bottomLeftRect.setColor(Color.parseColor("#FF5599"));
canvas.drawRect(0, y / 2, x / 2, y, bottomLeftRect);
//Draw the top tight rectangle
topRightRect.setStyle(Paint.Style.FILL);
//topRightRect.setColor(Color.WHITE);
topRightRect.setColor(Color.parseColor("#FF6600"));
//canvas.drawPaint(topRightRect);
canvas.drawRect(x / 2, 0, x, y / 3, topRightRect);
// Draw the middle right rectangle
midRightRect.setStyle(Paint.Style.FILL);
//midRightRect.setColor(Color.WHITE);
midRightRect.setColor(Color.parseColor("#66FFFF"));
// canvas.drawPaint(midRightRect);
canvas.drawRect(x / 2, y/3, x, 2*y / 3, midRightRect);
//Draw the bottom right rectangle
bottomRightRect.setStyle(Paint.Style.FILL);
//bottomRightRect.setColor(Color.WHITE);
bottomRightRect.setColor(Color.parseColor("#CCCC00"));
// canvas.drawPaint(bottomRightRect);
canvas.drawRect(x/2, 2*y/3, x, y, bottomRightRect);
}
}
Related
I successfully added an oval shape to the canvas, however now i'd like to add two more rectangles but for some reason they do not get added to the canvas. The oval shape is a ball which moves and rectangle shapes are static elements which are for "background". One rectangle should be as a floor and another one as an obstacle for the moving object, ball.
I tried to visualize it in the image:
This is the code, mBack and mObs are the rectangles i'm trying to add.
AnimatedView animatedView = null;
ShapeDrawable mDrawable = new ShapeDrawable();
ShapeDrawable mBack = new ShapeDrawable();
ShapeDrawable mJump = new ShapeDrawable();
public static int x;
public static int y;
public class AnimatedView extends ImageView {
static final int width = 50;
static final int height = 50;
public AnimatedView(Context context) {
super(context);
// TODO Auto-generated constructor stub
mDrawable = new ShapeDrawable(new OvalShape());
mBack = new ShapeDrawable(new RectShape());
mObs = new ShapeDrawable(new RectShape());
mDrawable.getPaint().setColor(0xffffAC23);
//mDrawable.setBounds(x, y, x + width, y + height);
mDrawable.setBounds(y, x, y + width, x + height);
mBack.setBounds(100, 100, 100, 100);
mObs.setBounds(120,120,120,120);
}
#Override
protected void onDraw(Canvas canvas) {
mDrawable.setBounds(y, x, y + width, x + height);
mBack.draw(canvas);
mDrawable.draw(canvas);
invalidate();
}
}
mDrawable will be added however mBack or mObs not. Adding setBounds to onDraw won't change a thing also.
The way you are setting Bounds is wrong. The definition of the setBounds method is here:
setBounds(int left, int top, int right, int bottom)
for the two rectangles you are setting it as
mBack.setBounds(100, 100, 100, 100);
mObs.setBounds(120,120,120,120);
This means you are left and right corners are same and top and bottom are same so you are not seeing your rectangle.
Set it something like this then you will see your rectangles
mBack.setBounds(100, 100, 300, 400);
And call draw method on both rectangle shapes in onDraw method.
It seems the problem is that for mBack you defined the bounds to zero pixel (start end ends in (100,100)), same for mObs, but for that you didn't call draw either.
I'm drawing text on canvas with this code:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
Rect bounds = new Rect();
paint.setColor(Color.BLACK);
paint.setTextSize(50);
paint.getTextBounds(first, 0, first.length(), bounds);
canvas.drawText(first, (canvas.getWidth() - bounds.width()) / 2, 50, paint);
}
Here is result:
But I want the text to have bigger height, I want something like this:
I don't want to change the font size, only the height of this text. How can i do this ?
I found solution for this:
// Closing hardware acceleration
setLayerType(LAYER_TYPE_SOFTWARE, paint);
paint.getTextBounds(first, 0, first.length(), bounds);
float posX = (canvas.getWidth() - bounds.width()) / 2; // center
float posY = ((canvas.getHeight() - bounds.height()) / 2); // center
canvas.scale(1, 10, posX, posY);
canvas.drawText(first, posX, posY, paint);
I'm currently trying to make a game, and I'm still novice with using cameras, and I'm thinking that two OrthographicCameras may be necessary, but I'm not sure if that's the most efficient way, or even how to do so.
Basically, I want this to be the layout for it:
The Main Area is where the main stuff is, which is a Server Interface. The Game Level is where the actual game part is in. I am currently using a ScissorStack to cut the region, but with this demo, results make me question how to do this:
public class TestScissorStackAndCamera extends ApplicationAdapter {
private SpriteBatch batch;
private OrthographicCamera camera;
private Sprite sprite;
private int width, height;
#Override
public void create() {
Gdx.gl.glClearColor(0, 0, 0, 0);
width = Gdx.graphics.getWidth();
height = Gdx.graphics.getHeight();
batch = new SpriteBatch();
camera = new OrthographicCamera(width, height);
camera.position.set(width / 2, height / 2, 0);
camera.update();
createSprite();
}
private void createSprite() {
Pixmap map = new Pixmap(width, height, Format.RGBA8888);
map.setColor(Color.RED);
map.fillRectangle(0, 0, width, height);
map.setColor(Color.BLUE);
map.drawLine(width / 2, 0, width / 2, height);
map.drawLine(0, height / 2, width, height / 2);
Texture texture = new Texture(map);
sprite = new Sprite(texture);
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined); // The Question!
batch.begin();
{
Rectangle scissors = new Rectangle();
Rectangle area = new Rectangle(10, 10, width - 20, height - 20);
ScissorStack.calculateScissors(camera, batch.getTransformMatrix(), area, scissors);
ScissorStack.pushScissors(scissors);
batch.draw(sprite, 0, 0);
batch.flush();
ScissorStack.popScissors();
}
batch.end();
}
public static void main(String[] args) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.title = "ScissorStack & Camera Test";
config.resizable = false;
new LwjglApplication(new TestScissorStackAndCamera(), config);
}
}
Questioning batch.setProjectionMatrix(camera.combined)
I marked a line in the code with a comment, The Question!, which is what is affecting the results. If I don't have it, using the camera.translate(...) method, the image is drawn at (0, 0) but what it does is it moves what part is viewed. If I do have that line, when I use the camera.translate(...) method, the image is drawn respectively to the position of the camera.
In respect to the game that I'm currently developing, it behaves awkwardly without the projectionMatrix not being set, but when I do set it, it messes up the positioning of the rest of the game. I even added some testing features, and it's not rendering inside of the correct ScissorStack
How could I go about setting up two cameras, or what could I do to set up what I'm trying to correctly and efficiently?
With my actual game (not the mock-up) this is what it is doing. It should be rendering inside of the red lines, but it's not:
If you'd like to see my current code for my GameLevel that is handling the ScissorStack and OrthographicCamera:
public GameLevel(int x, int y, int displayWidth, int displayHeight) {
this.x = x; // x = 10
this.y = y; // y = 10
this.displayWidth = displayWidth; // displayWidth = Gdx.graphics.getWidth() - x - 10
this.displayHeight = displayHeight; // displayHeight = Gdx.graphics.getHeight() - y - 120
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(displayWidth / 2, displayHeight / 2, 0);
// FBLAGame.batch.setProjectionMatrix(camera.combined);
camera.update();
init();
}
...
#Override
public void render() {
Rectangle area = new Rectangle(x, y, displayWidth, displayHeight);
Rectangle scissor = new Rectangle();
Matrix4 matrix = FBLAGame.batch.getTransformMatrix();
ScissorStack.calculateScissors(camera, matrix, area, scissor);
ScissorStack.pushScissors(scissor);
renderLevel();
FBLAGame.batch.flush();
ScissorStack.popScissors();
Pixmap map = new Pixmap(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), Format.RGBA8888);
map.setColor(Color.RED);
map.drawRectangle((int) area.x, (int) area.y, (int) area.width, (int) area.height);
Texture t = new Texture(map);
map.dispose();
FBLAGame.batch.draw(t, 0, 0);
}
I would like the camera to be positioned correctly but I am getting the result below:
It seems like when I resize the window, the map does not get rendered properly. Why does that happen?
Code:
public void render(float delta){
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
mapRenderer.setView(camera);
mapRenderer.render(background);
mapRenderer.render(foreground);
shapeRenderer.setProjectionMatrix(camera.combined);
//draw rectangles around walls
for(MapObject object : tiledMap.getLayers().get("walls").getObjects()){
if(object instanceof RectangleMapObject) {
RectangleMapObject rectObject = (RectangleMapObject) object;
Rectangle rect = rectObject.getRectangle();
shapeRenderer.begin(ShapeType.Line);
shapeRenderer.rect(rect.x, rect.y, rect.width, rect.height);
shapeRenderer.end();
}
}
//done drawing rectangles
}
#Override
public void resize(int width, int height) {
camera.viewportWidth = width;
camera.viewportHeight = height;
}
#Override
public void show(){
//call the tile map here
//I believe this is called first before render() is called
tiledMap = new TmxMapLoader().load("data/mapComplete.tmx");
mapRenderer = new OrthogonalTiledMapRenderer(tiledMap, 1f);
//initiate shapeRenderer. Can remove later
shapeRenderer = new ShapeRenderer();
shapeRenderer.setColor(Color.RED);
camera = new OrthographicCamera();
camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
This should center the camera at the viewport of the game.
#Override
public void resize(int width, int height) {
camera.viewportWidth = width;
camera.viewportHeight = height;
camera.position.set(width/2f, height/2f, 0); //by default camera position on (0,0,0)
}
You do not set the position of the camera anywhere. Thus it is looking at (0, 0) by default (which means (0, 0) will be in the center of your screen). The TiledMapRenderer renders the bottom left corner of the map at (0, 0) which means that it will fill the top right quadrant of your screen. That's what you see in your screenshot.
To set it to the center of the map, you could do something like the following:
TiledMapTileLayer layer0 = (TiledMapTileLayer) map.getLayers().get(0);
Vector3 center = new Vector3(layer0.getWidth() * layer0.getTileWidth() / 2, layer0.getHeight() * layer0.getTileHeight() / 2, 0);
camera.position.set(center);
How could I fill the green portion between two arcs shown below using the paint and canvas methods?
Here is how I draw the two arcs, I also could figure out how to connect them with lines but I don't know how I can fill the inner area.
// set to stroke black
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth((float) STROKE_WIDTH);
// outside arc
RectF arc_oval_outside = new RectF((float) (getX()), (float) (getY()),
(float) (getX() + getWidth()), (float) (getY() + getHeight()));
canvas.drawArc(arc_oval_outside, (float) (0.0), (45.0) (ARC_SWEEP), false, paint);
// inside arc
RectF arc_oval_inside = new RectF((float) (getX() + ARC_WIDTH), (float) (getY() + ARC_WIDTH),
(float) (getX() + getWidth() - ARC_WIDTH), (float) (getY() + getHeight() - ARC_WIDTH));
canvas.drawArc(arc_oval_inside, (float) (0.0), (float) (ARC_SWEEP), false, paint);
Here is a simple way to draw filled arc with border:
Point center = new Point(canvas.getWidth()/2, canvas.getHeight()/2);
int inner_radius = 100;
int outer_radius = 150;
int arc_sweep = 90;
int arc_ofset = 30;
RectF outer_rect = new RectF(center.x-outer_radius, center.y-outer_radius, center.x+outer_radius, center.y+outer_radius);
RectF inner_rect = new RectF(center.x-inner_radius, center.y-inner_radius, center.x+inner_radius, center.y+inner_radius);
Path path = new Path();
path.arcTo(outer_rect, arc_ofset, arc_sweep);
path.arcTo(inner_rect, arc_ofset + arc_sweep, -arc_sweep);
path.close();
Paint fill = new Paint();
fill.setColor(Color.GREEN);
canvas.drawPath(path, fill);
Paint border = new Paint();
border.setStyle(Paint.Style.STROKE);
border.setStrokeWidth(2);
canvas.drawPath(path, border);
(The Path and Paint allocation is made to be clear not optimal)
I Know it could be a little bit late but I came with this approach from a iOS project, first draw contour and then draw the filling arc
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float width = (float)getWidth();
float height = (float)getHeight();
float radius;
//Get radius from the bigger size
if (width > height){
radius = height/2;
}else{
radius = width/2;
}
//Create Paint Object
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setFilterBitmap(true);
paint.setAntiAlias(true);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
//Create Contour Object
Path path = new Path();
float center_x, center_y;
center_x = width/2;
center_y = height/2;
//Configure rect for the outer ring
final RectF oval = new RectF();
oval.set(center_x - radius + 5,
center_y - radius + 5,
center_x + radius - 5,
center_y + radius - 5);
//Add outer arc
path.addArc(oval, 0, 90);
//Configure rect for the inner ring
oval.set(center_x - radius + 30,
center_y - radius + 30,
center_x + radius - 30,
center_y + radius - 30);
//Add inner arc to the path but draw counterclockwise
path.arcTo(oval, -270, -90);
//close path
path.close();
//Create Paint Object
Paint fillPaint = new Paint();
fillPaint.setColor(Color.YELLOW);
fillPaint.setFilterBitmap(true);
fillPaint.setAntiAlias(true);
fillPaint.setStrokeWidth(21);
fillPaint.setStyle(Paint.Style.STROKE);
//Create Contour Object
Path fillPath = new Path();
//Configure rect for the fill ring
oval.set(center_x - radius + 17,
center_y - radius + 17,
center_x + radius - 17,
center_y + radius - 17);
//Add fill arc
fillPath.addArc(oval, 0, 90);
//draw fill path
canvas.drawPath(fillPath,fillPaint);
//draw outer path
canvas.drawPath(path, paint);
}
A helpfull link: http://www.programering.com/a/MDO1czNwATE.html where addarc maths are quite well explained
Just posting another option using drawArc only. Basically we first draw the outer filled arc and then we draw the smaller inner arc using PorterDuff.Mode.CLEAR to erase and achieve the asked above.
Bitmap b = Bitmap.createBitmap(1200, 1200, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(b);
int radius = 40;
float startAngle = 45f; // your start angle
float sweepAngle = 90f; // your sweep angle
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.rgb(37, 181, 215));
paint.setStyle(Paint.Style.FILL);
// draw outer arc
RectF oval = new RectF(0, 0, canvas.getWidth(), canvas.getHeight());
canvas.drawArc(oval, startAngle, sweepAngle, true, paint);
// draw inner arc
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
oval = new RectF((canvas.getWidth() / 2) - radius, (canvas.getHeight() / 2) - radius, (canvas.getWidth() / 2) + radius, (canvas.getHeight() / 2) + radius);
canvas.drawArc(oval, startAngle, sweepAngle, true, paint);
ImageView.setImageBitmap(b);
Hope it helps someone.