I'm struggling with adding a map scale that displays current length on screen depending on current zoom level. I'm having a feeling that it might exist some predefined class to use but I have no clue...? I've searched around a lot but can't find anything.
Any help i much appreciated =)
// Alex
Alright, I got it now! Luis answer helped me a lot and also OpenStreetMap. Here's what I came up with:
<your.own.package.path>;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Picture;
import android.graphics.Rect;
import android.location.Location;
import android.util.Log;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;
import com.iqqn.uppgift5.GameMapActivity;
public class ScaleBarOverlay extends Overlay{
// ===========================================================
// Fields
// ===========================================================
// Defaults
boolean enabled = true;
float xOffset = 10;
float yOffset = 10;
float lineWidth = 2;
int textSize = 12;
boolean imperial = false;
boolean nautical = false;
boolean latitudeBar = true;
boolean longitudeBar = false;
// Internal
protected final MapView mapView;
protected final GameMapActivity master;
private Context context;
protected final Picture scaleBarPicture = new Picture();
private final Matrix scaleBarMatrix = new Matrix();
private int lastZoomLevel = -1;
float xdpi;
float ydpi;
int screenWidth;
int screenHeight;
// ===========================================================
// Constructors
// ===========================================================
public ScaleBarOverlay(Context _context, GameMapActivity master, MapView mapView) {
super();
this.master = master;
this.context = _context;
this.mapView = mapView;
xdpi = this.context.getResources().getDisplayMetrics().xdpi;
ydpi = this.context.getResources().getDisplayMetrics().ydpi;
screenWidth = this.context.getResources().getDisplayMetrics().widthPixels;
screenHeight = this.context.getResources().getDisplayMetrics().heightPixels;
}
// ===========================================================
// Getter & Setter
// ===========================================================
/**
* #return the enabled
*/
public boolean isEnabled() {
return enabled;
}
/**
* #param enabled the enabled to set
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/**
* #return the lineWidth
*/
public float getLineWidth() {
return lineWidth;
}
/**
* #param lineWidth the lineWidth to set
*/
public void setLineWidth(float lineWidth) {
this.lineWidth = lineWidth;
}
/**
* #return the imperial
*/
public boolean isImperial() {
return imperial;
}
/**
* #param imperial the imperial to set
*/
public void setImperial() {
this.imperial = true;
this.nautical = false;
createScaleBarPicture();
}
/**
* #return the nautical
*/
public boolean isNautical() {
return nautical;
}
/**
* #param nautical the nautical to set
*/
public void setNautical() {
this.nautical = true;
this.imperial = false;
createScaleBarPicture();
}
public void setMetric() {
this.nautical = false;
this.imperial = false;
createScaleBarPicture();
}
public void drawLatitudeScale(boolean latitude) {
this.latitudeBar = latitude;
}
public void drawLongitudeScale(boolean longitude) {
this.longitudeBar = longitude;
}
#Override
public void draw(Canvas canvas, MapView localMapView, boolean shadow) {
if (this.enabled) {
// Draw the overlay
if (shadow == false) {
final int zoomLevel = localMapView.getZoomLevel();
if (zoomLevel != lastZoomLevel) {
lastZoomLevel = zoomLevel;
createScaleBarPicture();
}
this.scaleBarMatrix.setTranslate(-1 * (scaleBarPicture.getWidth() / 2 - 0.5f), -1 * (scaleBarPicture.getHeight() / 2 - 0.5f));
this.scaleBarMatrix.postTranslate(xdpi/2, ydpi/2 + canvas.getHeight()-50);
canvas.save();
canvas.setMatrix(scaleBarMatrix);
canvas.drawPicture(scaleBarPicture);
canvas.restore();
}
}
}
// ===========================================================
// Methods
// ===========================================================
public void disableScaleBar() {
this.enabled = false;
}
public boolean enableScaleBar() {
return this.enabled = true;
}
private void createScaleBarPicture() {
// We want the scale bar to be as long as the closest round-number miles/kilometers
// to 1-inch at the latitude at the current center of the screen.
Projection projection = mapView.getProjection();
if (projection == null) {
return;
}
Location locationP1 = new Location("ScaleBar location p1");
Location locationP2 = new Location("ScaleBar location p2");
// Two points, 1-inch apart in x/latitude, centered on screen
GeoPoint p1 = projection.fromPixels((int) ((screenWidth / 2) - (xdpi / 2)), screenHeight/2);
GeoPoint p2 = projection.fromPixels((int) ((screenWidth / 2) + (xdpi / 2)), screenHeight/2);
locationP1.setLatitude(p1.getLatitudeE6()/1E6);
locationP2.setLatitude(p2.getLatitudeE6()/1E6);
locationP1.setLongitude(p1.getLongitudeE6()/1E6);
locationP2.setLongitude(p2.getLongitudeE6()/1E6);
float xMetersPerInch = locationP1.distanceTo(locationP2);
p1 = projection.fromPixels(screenWidth/2, (int) ((screenHeight / 2) - (ydpi / 2)));
p2 = projection.fromPixels(screenWidth/2, (int) ((screenHeight / 2) + (ydpi / 2)));
locationP1.setLatitude(p1.getLatitudeE6()/1E6);
locationP2.setLatitude(p2.getLatitudeE6()/1E6);
locationP1.setLongitude(p1.getLongitudeE6()/1E6);
locationP2.setLongitude(p2.getLongitudeE6()/1E6);
float yMetersPerInch = locationP1.distanceTo(locationP2);
final Paint barPaint = new Paint();
barPaint.setColor(Color.BLACK);
barPaint.setAntiAlias(true);
barPaint.setStyle(Style.FILL);
barPaint.setAlpha(255);
final Paint textPaint = new Paint();
textPaint.setColor(Color.BLACK);
textPaint.setAntiAlias(true);
textPaint.setStyle(Style.FILL);
textPaint.setAlpha(255);
textPaint.setTextSize(textSize);
final Canvas canvas = scaleBarPicture.beginRecording((int)xdpi, (int)ydpi);
if (latitudeBar) {
String xMsg = scaleBarLengthText(xMetersPerInch, imperial, nautical);
Rect xTextRect = new Rect();
textPaint.getTextBounds(xMsg, 0, xMsg.length(), xTextRect);
int textSpacing = (int)(xTextRect.height() / 5.0);
canvas.drawRect(xOffset, yOffset, xOffset + xdpi, yOffset + lineWidth, barPaint);
canvas.drawRect(xOffset + xdpi, yOffset, xOffset + xdpi + lineWidth, yOffset + xTextRect.height() + lineWidth + textSpacing, barPaint);
if (!longitudeBar) {
canvas.drawRect(xOffset, yOffset, xOffset + lineWidth, yOffset + xTextRect.height() + lineWidth + textSpacing, barPaint);
}
canvas.drawText(xMsg, (xOffset + xdpi/2 - xTextRect.width()/2), (yOffset + xTextRect.height() + lineWidth + textSpacing), textPaint);
}
if (longitudeBar) {
String yMsg = scaleBarLengthText(yMetersPerInch, imperial, nautical);
Rect yTextRect = new Rect();
textPaint.getTextBounds(yMsg, 0, yMsg.length(), yTextRect);
int textSpacing = (int)(yTextRect.height() / 5.0);
canvas.drawRect(xOffset, yOffset, xOffset + lineWidth, yOffset + ydpi, barPaint);
canvas.drawRect(xOffset, yOffset + ydpi, xOffset + yTextRect.height() + lineWidth + textSpacing, yOffset + ydpi + lineWidth, barPaint);
if (! latitudeBar) {
canvas.drawRect(xOffset, yOffset, xOffset + yTextRect.height() + lineWidth + textSpacing, yOffset + lineWidth, barPaint);
}
float x = xOffset + yTextRect.height() + lineWidth + textSpacing;
float y = yOffset + ydpi/2 + yTextRect.width()/2;
canvas.rotate(-90, x, y);
canvas.drawText(yMsg, x, y + textSpacing, textPaint);
}
scaleBarPicture.endRecording();
}
private String scaleBarLengthText(float meters, boolean imperial, boolean nautical) {
if (this.imperial) {
if (meters >= 1609.344) {
return (meters / 1609.344) + "mi";
} else if (meters >= 1609.344/10) {
return ((meters / 160.9344) / 10.0) + "mi";
} else {
return (meters * 3.2808399) + "ft";
}
} else if (this.nautical) {
if (meters >= 1852) {
return ((meters / 1852)) + "nm";
} else if (meters >= 1852/10) {
return (((meters / 185.2)) / 10.0) + "nm";
} else {
return ((meters * 3.2808399)) + "ft";
}
} else {
if (meters >= 1000) {
return ((meters / 1000)) + "km";
} else if (meters > 100) {
return ((meters / 100.0) / 10.0) + "km";
} else {
return meters + "m";
}
}
}
#Override
public boolean onTap(GeoPoint point, MapView mapView) {
// Do not react to screen taps.
return false;
}
}
Use it the following way in your onCreate():
...
scaleBarOverlay = new ScaleBarOverlay(this.getBaseContext(), this, myMapView);
List<Overlay> overlays = myMapView.getOverlays();
// Add scale bar overlay
scaleBarOverlay.setMetric();
overlays.add(scaleBarOverlay);
...
Hope this will help anyone =) This will work from API level 7+. I haven't tested it on API level 14+ though, and i know that some hardware accelerated stuff "don't" work there like drawing a picture with canvas. But i think it'll work with a recording.
Thanks again Luis!
// Alexander
As far as I know there isn't a predifined class to do that.
One possibility is to create an overlay that checks current longitude span, as it changes accordingly to latitude, and then draw the scale at the correct size.
Bellow you can find an example on how to do that:
ScaleBar Overlay
public class CopyOfScaleBarOverlay extends Overlay {
private static final String STR_M = "m";
private static final String STR_KM = "km";
//Constants
private static float scaleBarProportion = 0.25f;
private float cMarginLeft=4;
private float cLineTopSize=8;
private float cMarginTop=6;
private float cMarginBottom=2;
private float cTextSize=12;
private float distanceFromBottom=100;
//instantiation
private Context context;
private Paint paintLine, paintText, paintRectangle;
private Location l0;
private Location l1;
private float ds;
private int width, height, pi;
private float marginLeft, marginTop, marginBottom, lineTopSize;
private String unit;
public CopyOfScaleBarOverlay(Context context){
super();
this.context=context;
paintText= new TextPaint();
paintText.setARGB(180, 0, 0, 0);
paintText.setAntiAlias(true);
paintText.setTextAlign(Align.CENTER);
paintRectangle = new Paint();
paintRectangle.setARGB(80,255,255,255);
paintRectangle.setAntiAlias(true);
paintLine = new Paint();
paintLine.setARGB(180, 0, 0, 0);
paintLine.setAntiAlias(true);
l0 = new Location("none");
l1 = new Location("none");
ds=this.context.getApplicationContext().getResources().getDisplayMetrics().density;
width=this.context.getApplicationContext().getResources().getDisplayMetrics().widthPixels;
height=this.context.getApplicationContext().getResources().getDisplayMetrics().heightPixels;
pi = (int) (height - distanceFromBottom *ds);
marginLeft=cMarginLeft*ds;
lineTopSize=cLineTopSize*ds;
marginTop=cMarginTop*ds;
marginBottom=cMarginBottom*ds;
}
#Override
public void draw(Canvas canvas, MapView mapview, boolean shadow) {
super.draw(canvas, mapview, shadow);
if(mapview.getZoomLevel() > 1){
//Calculate scale bar size and units
GeoPoint g0 = mapview.getProjection().fromPixels(0, height/2);
GeoPoint g1 = mapview.getProjection().fromPixels(width, height/2);
l0.setLatitude(g0.getLatitudeE6()/1E6);
l0.setLongitude(g0.getLongitudeE6()/1E6);
l1.setLatitude(g1.getLatitudeE6()/1E6);
l1.setLongitude(g1.getLongitudeE6()/1E6);
float d01=l0.distanceTo(l1);
float d02=d01*scaleBarProportion;
// multiply d02 by a unit conversion factor if needed
float cd02;
if(d02 > 1000){
unit = STR_KM;
cd02 = d02 / 1000;
} else{
unit = STR_M;
cd02 = d02;
}
int i=1;
do{
i *=10;
}while (i <= cd02);
i/=10;
float dcd02=(int)(cd02/i)*i;
float bs=dcd02*width/d01*d02/cd02;
String text=String.format("%.0f %s", dcd02, unit);
paintText.setTextSize(cTextSize * ds);
float text_x_size=paintText.measureText(text);
float x_size = bs + text_x_size/2 + 2*marginLeft;
//Draw rectangle
canvas.drawRect(0,pi,x_size,pi+marginTop+paintText.getFontSpacing()+marginBottom, paintRectangle);
//Draw line
canvas.drawLine(marginLeft, pi+marginTop, marginLeft + bs, pi+marginTop, paintLine);
//Draw line tops
canvas.drawLine(marginLeft, pi+marginTop - lineTopSize/2, marginLeft, pi+marginTop + lineTopSize/2, paintLine);
canvas.drawLine(marginLeft +bs, pi+marginTop - lineTopSize/2, marginLeft+bs, pi+marginTop + lineTopSize/2, paintLine);
//Draw line midle
canvas.drawLine(marginLeft + bs/2, pi+marginTop - lineTopSize/3, marginLeft + bs/2, pi+marginTop + lineTopSize/3, paintLine);
//Draw line quarters
canvas.drawLine(marginLeft + bs/4, pi+marginTop - lineTopSize/4, marginLeft + bs/4, pi+marginTop + lineTopSize/4, paintLine);
canvas.drawLine(marginLeft + 3*bs/4, pi+marginTop - lineTopSize/4, marginLeft + 3*bs/4, pi+marginTop + lineTopSize/4, paintLine);
//Draw text
canvas.drawText(text, marginLeft +bs, pi+marginTop+paintText.getFontSpacing(), paintText);
}
}
}
To use
On your activity that extendes MapActivity, add the following:
mapView.getOverlays().add(new CopyOfScaleBarOverlay(this));
Note
The example is using metric units. To use a different unit system, multiply d02 in the code above by a unit conversion factor and adjust strings with the unit name.
Enjoy it.
Related
Can I get a clarification on how to figure out the point in which 2 line segments intersect?
I have this code in which I am creating a pong game but I am having trouble with figuring out where the ball intersects with the paddle and if so basically bounce it back. I know some basic algebra is needed but for the sake of my code what is needed?
I have the current position of the ball, the old position of the ball, and the paddles current position (ballX,Y , oldBallX,Y , etc) What would I have to do to get the (x, y) intersection point for the collision of the ball on the paddle?
CODE
`
package com.example.pong;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Region;
import android.media.MediaPlayer;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import androidx.annotation.NonNull;
public class PongView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private static final String TAG = "";
private final GameActivity gameActivity;
private Thread _thread;
private int screenWidth; // screen width
private int screenHeight; // screen height
Context _context;
private SurfaceHolder _surfaceHolder;
private boolean _run = false;
// All pong variables go in here
// Right Paddle
private float rPaddle; // variable set by touch event
// Left Paddle
private float lPaddle; // variable set by touch event
// Paddle variables
private int halfPaddle = 50;
private final static int MAX_FPS = 30; //desired fps
private final static int FRAME_PERIOD = 1000 / MAX_FPS; // the frame period
private Paint background = new Paint();
private Paint dark = new Paint();
private float ballX = 500.0f; // ball location
private float ballY = 250.0f;
/// pongSpeed variables
public float pongSpeed = 1.0f;
private long mLastTime = Long.MAX_VALUE;
private float timeElapsed; // Time since last frame in seconds
// The speed in pixels per second
private float ballSpeedX = 300.0f;
private float ballSpeedY = 300.0f;
// Variables for current pong position
private float oldBallX = 0.0f;
private float oldBallY = 0.0f;
private float xPos = 0.0f;
private float yPos = 0.0f;
private float xDir = 1.0f;
private float yDir = 1.0f;
//
public PongView(Context context) {
super(context);
_surfaceHolder = getHolder();
getHolder().addCallback(this);
this.gameActivity = (GameActivity) context;
_context = context;
setFocusable(true);
setFocusableInTouchMode(true);
}
//
public void setRPaddle(float rp) {
synchronized (_surfaceHolder) {
rPaddle = rp;
}
}
public void setLPaddle(float lp) {
synchronized (_surfaceHolder) {
lPaddle = lp;
}
}
#Override
public void run() {
float avg_sleep = 0.0f;
float fcount = 0.0f;
long fps = System.currentTimeMillis();
Canvas c;
while (_run) {
c = null;
long started = System.currentTimeMillis();
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
// Update game state
update();
}
// draw image
drawImage(c);
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
float deltaTime = (System.currentTimeMillis() - started);
int sleepTime = (int) (FRAME_PERIOD - deltaTime);
if (sleepTime > 0) {
try {
_thread.sleep(sleepTime);
}
catch (InterruptedException e) {
}
}
}
}
public void pause() {
_run = false;
boolean retry = true;
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
}
public void initialize(int w, int h) {
screenWidth = w;
screenHeight = h;
// create paints, rectangles, init time, etc
background.setColor(0xff200040); // should really get this from resource file
dark.setColor(0xffdddddd);
}
protected void update() {
// game update goes here
int width = getWidth();
int height = getHeight();
MediaPlayer pip = MediaPlayer.create(_context.getApplicationContext(), R.raw.lil_pip);
long now = System.currentTimeMillis(); // Current time
if (now > mLastTime)
{
timeElapsed = (now - mLastTime) / 1000.0f;
}
mLastTime = now;
ballX += ballSpeedX * timeElapsed;
ballY += ballSpeedY * timeElapsed;
oldBallX = ballX;
oldBallY = ballY;
collisionCheck();
//Treat paddle as line segment. Treat ball positions as points.
//Change ball direction if the two line segments intersect.
}
protected void collisionCheck()
{
// Bounce right side
if ((ballX > screenWidth) && (ballSpeedX > 0.0f))
{
ballSpeedX *= -1.0f;
pip.start();
}
// Bounce left side
// Not sure if using "80 *" is the best
if ((80 * ballX < screenHeight) && (ballSpeedX < 0.0f))
{
ballSpeedX *= -1.0f;
pip.start();
}
// Bounce bottom side
if ((ballY > screenHeight) && (ballSpeedY > 0.0f))
{
ballSpeedY *= -1.0f;
pip.start();
}
// Bounce top side
// Not sure if using "80 *" is the best
if ((80 * ballY < screenHeight) && (ballSpeedY < 0.0f))
{
ballSpeedY *= -1.0f;
pip.start();
}
Log.d("TAG", "Ball is moving");
}
private void rightPaddle (Canvas canvas)
{
canvas.drawRect(7 * screenWidth / 8, rPaddle * screenHeight + halfPaddle,
7 * screenWidth / 8 + 15, rPaddle * screenHeight - halfPaddle, dark);
}
private void leftPaddle (Canvas canvas)
{
canvas.drawRect( screenWidth / 8, lPaddle * screenHeight + halfPaddle,
screenWidth / 8 + 15, lPaddle * screenHeight - halfPaddle, dark);
}
private void pongBall (Canvas canvas)
{
canvas.drawRect(ballX, ballY, ballX + 10, ballY + 10, dark);
}
protected void drawImage(Canvas canvas) {
if (canvas == null) return;
// Draw commands go here
// Draw commands go here
canvas.drawRect(0, 0, getWidth(), getHeight(), background);
pongBall(canvas);
rightPaddle(canvas);
leftPaddle(canvas);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
screenWidth = w;
screenHeight = h;
super.onSizeChanged(w, h, oldw, oldh);
initialize(w, h);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
_run = true;
_thread = new Thread(this);
_thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// simply copied from sample application LunarLander:
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
_run = false;
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int numPointers = event.getPointerCount();
int ptrIdx = 0;
while (ptrIdx < numPointers) {
int id = event.getPointerId(ptrIdx);
float xp = event.getX(ptrIdx) / screenWidth;
if (xp > 0.6) {
setRPaddle(event.getY(ptrIdx) / screenHeight);
} else if (xp < 0.4) {
setLPaddle(event.getY(ptrIdx) / screenHeight);
}
if ((ptrIdx > 0) || (id > 0)) {
Log.i(TAG, " Feel the power..." + ptrIdx + " " + id);
}
ptrIdx++;
}
return true;
}
}
`
I've tried making the paddles into Path's but my confusion is what exactly am I using for x1, x2, y1, y2 to find out the point of intersection.
You have to know some basic algebra knowledge. A line can be written in the form of Ax + By + C = 0 in a plain. (See Wikipedia-Line)
To calculate the intersect, you may first calculate the equation of the two lines.
A line passing from (x1, y1) and (x2, y2) can be written in the form of (y1 - y2) * x + (x2 - x1) * y + (x1 * y2 - x2 * y1) = 0. This way, you can calculate the equation of the two lines.
Now, you get the equation of the two lines. Say A1 * x + B1 * y + C1 = 0 and A2 * x + B2 * y + C2 = 0. Then the x-coordinate of the intersect will be (C2 * B1 - C1 * B2) / (A1 * B2 - A2 * B1), and the y-coordinate will be (C1 * A2 - C2 * A1) / (A1 * B2 - A2 * B1). Thus, you get the intersect.
Im making a virtual joystick controller using SurfaceView but the drawn shapes in my java code is not rendered in the design view, im very new to java with just a few months experience.
public class JoystickView extends SurfaceView
implements SurfaceHolder.Callback,
View.OnTouchListener
{
private float centerX;
private float centerY;
private float baseRadius;
private float hatRadius;
private JoystickListener joystickCallback;
private void setupDimensions()
{
centerX = (float)getWidth()/2;
centerY = (float)getHeight()/2;
baseRadius = (float)Math.min(getWidth(), getHeight())/3;
hatRadius = (float)Math.min(getWidth(), getHeight())/5;
}
public JoystickView(Context context)
{
super(context);
getHolder().addCallback(this);
setOnTouchListener(this);
if(context instanceof JoystickListener){
joystickCallback = (JoystickListener) context;}
}
public JoystickView(Context context, AttributeSet attributes, int style)
{
super(context, attributes, style);
getHolder().addCallback(this);
setOnTouchListener(this);
}
public JoystickView(Context context, AttributeSet attributes)
{
super(context, attributes);
getHolder().addCallback(this);
setOnTouchListener(this);
}
This is where the joystick circle base and top(hat) where drawn using myCanvas.drawCircle()enter image description here
private void drawJoystick(float newX, float newY)
{
if(getHolder().getSurface().isValid())
{
Canvas myCanvas = this.getHolder().lockCanvas();
Paint colors = new Paint();
myCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
//These equations determine the sin and cos of the angle that the touched point is at relative to the center of the joystick
float hypotenuse = (float) Math.sqrt(Math.pow(newX - centerX, 2) + Math.pow(newY - centerY, 2));
float sin = (newY - centerY)/ hypotenuse;
float cos = (newX - centerX)/ hypotenuse;
//Drawing the base then shading
colors.setARGB(255, 50, 50, 50);
myCanvas.drawCircle(centerX, centerY, baseRadius, colors);
int ratio = 5;
for(int i = 1; i <= (int)(baseRadius/ ratio); i++)
{
colors.setARGB(150/i, 255, 0, 0); // Gradually reduce the black drawn to create an nice effect
myCanvas.drawCircle(newX- cos * hypotenuse * (ratio /baseRadius) * i,
newY - sin * hypotenuse * (ratio /baseRadius) * i, i * (hatRadius* ratio /baseRadius),colors); //gradually increase the size of the shading effect
}
//Drawing the joystick hat
for(int i = 1; i <= (int) (hatRadius / ratio); i++)
{
colors.setARGB(255, (int) (i * (255 * ratio / hatRadius)),(int)(i * (255 * ratio / hatRadius)), 255);//Change the joystick color for shading purposes
myCanvas.drawCircle(newX,newY, hatRadius - (float) i*(ratio) / 2, colors); // Drawing the shading of the hat
}
getHolder().unlockCanvasAndPost(myCanvas); //This writes the new drawing to the SurfaceView
}
}
#Override
public void surfaceCreated(SurfaceHolder holder)
{
setupDimensions();
drawJoystick(centerX, centerY);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
}
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
}
public boolean onTouch(View v, MotionEvent e)
{
if(v.equals(this)) {
if (e.getAction() != MotionEvent.ACTION_UP)
{
float displacement = (float) Math.sqrt((Math.pow(e.getX() - centerX, 2)) + Math.pow(e.getY() - centerY, 2));
if (displacement < baseRadius)
{
drawJoystick(e.getX(), e.getY());
joystickCallback.onJoystickMoved((e.getX() - centerX)/baseRadius, (e.getY() - centerY)/baseRadius, getId());
}
else {
float ratio = baseRadius / displacement;
float constrainedX = centerX + (e.getX() - centerX) * ratio;
float constrainedY = centerY + (e.getY() - centerY) * ratio;
drawJoystick(constrainedX, constrainedY);
joystickCallback.onJoystickMoved((constrainedX-centerX)/baseRadius, (constrainedY-centerY)/baseRadius, getId());
}
}
else
drawJoystick(centerX, centerY);
joystickCallback.onJoystickMoved(0,0, getId());
}
return true;
}
public interface JoystickListener
{
void onJoystickMoved(float xPercent, float yPercent, int id);
}
}
I am creating a 3d game using Java LWJGL and OpenGL. I want to be able to display a players health bar to the screen. I was thinking some kind of screen that I can render after my game is rendered, that will handle all the 2d 'UI-like' elements that need to be rendered to the screen. What is the best practice at doing this? I have tried creating a Screen class and painting using the Graphics class, but I have run into problems with this. I want a simplistic method that will work to render these elements. How is this done??
EDIT:
Here are some files that I think would be useful
MasterRenderer:
package renderEngine;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import models.TexturedModel;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Matrix4f;
import shaders.StaticShader;
import shaders.TerrainShader;
import terrains.Terrain;
import entities.Camera;
import entities.Entity;
import entities.Light;
public class MasterRenderer {
private static final float FOV = 70;
private static final float NEAR_PLANE = 0.1f;
private static final float FAR_PLANE = 1000;
private static final float RED = 0.5f;
private static final float GREEN = 0.90f;
private static final float BLUE = 0.90f;
private GUI gui = new GUI();
private Matrix4f projectionMatrix;
private StaticShader shader = new StaticShader();
private EntityRenderer renderer;
private Map<TexturedModel, List<Entity>> entities = new HashMap<TexturedModel, List<Entity>>();
private List<Terrain> terrains = new ArrayList<Terrain>();
private TerrainRenderer terrainRenderer;
private TerrainShader terrainShader = new TerrainShader();
public MasterRenderer() {
enableCulling();
createProjectionMatrix();
renderer = new EntityRenderer(shader, projectionMatrix);
terrainRenderer = new TerrainRenderer(terrainShader, projectionMatrix);
}
public static void enableCulling() {
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glCullFace(GL11.GL_BACK);
}
public static void disableCulling() {
GL11.glDisable(GL11.GL_CULL_FACE);
}
public void prepare() {
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT|GL11.GL_DEPTH_BUFFER_BIT);
GL11.glClearColor(RED, GREEN, BLUE, 1);
}
public void render(Light sun, Camera camera) {
prepare();
shader.start();
shader.loadSkyColour(RED,GREEN,BLUE);
shader.loadLight(sun);
shader.loadViewMatrix(camera);
renderer.render(entities);
shader.stop();
terrainShader.start();
terrainShader.loadLight(sun);
terrainShader.loadViewMatrix(camera);
terrainShader.loadSkyColour(RED,GREEN,BLUE);
terrainRenderer.render(terrains);
terrainShader.stop();
gui.drawRect(100, 100, 300, 300, 0x00000000);
terrains.clear();
entities.clear();
}
public void processTerrain(Terrain terrain) {
terrains.add(terrain);
}
public void processEntity(Entity entity) {
TexturedModel entityModel = entity.getModel();
List<Entity> batch = entities.get(entityModel);
if(batch != null) {
batch.add(entity);
} else {
List<Entity> newBatch = new ArrayList<Entity>();
newBatch.add(entity);
entities.put(entityModel, newBatch);
}
}
private void createProjectionMatrix() {
float aspectRatio = (float) Display.getWidth() / (float) Display.getHeight();
float y_scale = (float) ((1f / Math.tan(Math.toRadians(FOV / 2f))) * aspectRatio);
float x_scale = y_scale / aspectRatio;
float frustum_length = FAR_PLANE - NEAR_PLANE;
projectionMatrix = new Matrix4f();
projectionMatrix.m00 = x_scale;
projectionMatrix.m11 = y_scale;
projectionMatrix.m22 = -((FAR_PLANE + NEAR_PLANE) / frustum_length);
projectionMatrix.m23 = -1;
projectionMatrix.m32 = -((2 * NEAR_PLANE * FAR_PLANE) / frustum_length);
projectionMatrix.m33 = 0;
}
public void cleanUp() {
shader.cleanUp();
terrainShader.cleanUp();
}
}
Camera.java:
package entities;
import org.lwjgl.input.Mouse;
import org.lwjgl.util.vector.Vector3f;
public class Camera {
private float distanceFromPlayer = 50;
private float angleAroundPlayer = 0;
private Vector3f position = new Vector3f(0,0,0);
private float pitch = 20; //rotation
private float yaw = 0; //left or right
private float roll; //Tilted
private Player player;
public Camera(Player player) {
this.player = player;
}
public void move() {
calculateZoom();
calculatePitch();
calculateAngleAroundPlayer();
float horizontalDistance = calculateHorizontalDistance();
float verticalDistance = calculateVerticalDistance();
calculateCameraPosition(horizontalDistance, verticalDistance);
this.yaw = 180 - (player.getRotY() + angleAroundPlayer);
}
public float getAngleAroundPlayer() {
return angleAroundPlayer;
}
public Vector3f getPosition() {
return position;
}
public float getPitch() {
return pitch;
}
public float getYaw() {
return yaw;
}
public float getRoll() {
return roll;
}
public void setAngleAroundPlayer(float angleAroundPlayer) {
this.angleAroundPlayer = angleAroundPlayer;
}
private void calculateCameraPosition(float horizDistance, float verticDistance) {
float theta = player.getRotY() + angleAroundPlayer;
float offsetX = (float) (horizDistance * Math.sin(Math.toRadians(theta)));
float offsetZ = (float) (horizDistance * Math.cos(Math.toRadians(theta)));
position.x = player.getPosition().x - offsetX;
position.z = player.getPosition().z - offsetZ;
position.y = player.getPosition().y + verticDistance + 10;
}
private float calculateHorizontalDistance() {
return (float) (distanceFromPlayer * Math.cos(Math.toRadians(pitch)));
}
private float calculateVerticalDistance() {
return (float) (distanceFromPlayer * Math.sin(Math.toRadians(pitch)));
}
private void calculateZoom() {
float zoomLevel = Mouse.getDWheel() * 0.1f;
distanceFromPlayer -= zoomLevel;
}
private void calculatePitch() {
if(Mouse.isButtonDown(1)) {
float pitchChange = Mouse.getDY() * 0.1f;
pitch -= pitchChange;
if(pitch < 10) pitch = 10;
if(pitch > 90) pitch = 90;
}
}
private void calculateAngleAroundPlayer() {
if(Mouse.isButtonDown(0)) {
float angleChange = Mouse.getDX() * 0.3f;
if(angleAroundPlayer >= 360) angleAroundPlayer = 0;
angleAroundPlayer -= angleChange;
}
}
}
MainGameLoop:
package engineTester;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import models.TexturedModel;
import org.lwjgl.opengl.Display;
import org.lwjgl.util.vector.Vector3f;
import renderEngine.DisplayManager;
import renderEngine.Loader;
import renderEngine.MasterRenderer;
import renderEngine.OBJLoader;
import terrains.Terrain;
import textures.ModelTexture;
import textures.TerrainTexture;
import textures.TerrainTexturePack;
import toolbox.KeyBindings;
import entities.Camera;
import entities.Entity;
import entities.Light;
import entities.Player;
public class MainGameLoop {
public static KeyBindings keyBindings;
public static Camera camera;
public static void main(String[] args) {// TODO Auto-generated method stub
DisplayManager.createDisplay();
Loader loader = new Loader();
//--------------------Terrain Texture------------------//
TerrainTexture backgroundTexture = new TerrainTexture(loader.loadTexture("grassy2"));
TerrainTexture rTexture = new TerrainTexture(loader.loadTexture("mud"));
TerrainTexture gTexture = new TerrainTexture(loader.loadTexture("pinkFlowers"));
TerrainTexture bTexture = new TerrainTexture(loader.loadTexture("stone"));
TerrainTexturePack texturePack = new TerrainTexturePack(backgroundTexture, rTexture,
gTexture, bTexture);
TerrainTexture blendMap = new TerrainTexture(loader.loadTexture("blendMap"));
//-----------------------------------------------------//
ModelTexture fernTextureAtlas = new ModelTexture(loader.loadTexture("fern"));
fernTextureAtlas.setNumberOfRows(2);
TexturedModel tree1 = new TexturedModel(OBJLoader.loadObjModel("tree", loader),
new ModelTexture(loader.loadTexture("tree")));
TexturedModel tree2 = new TexturedModel(OBJLoader.loadObjModel("lowPolyTree", loader),
new ModelTexture(loader.loadTexture("lowPolyTree")));
TexturedModel fern = new TexturedModel(OBJLoader.loadObjModel("fern", loader),
fernTextureAtlas);
TexturedModel flower = new TexturedModel(OBJLoader.loadObjModel("grassModel", loader),
new ModelTexture(loader.loadTexture("flower")));
TexturedModel stall = new TexturedModel(OBJLoader.loadObjModel("stall", loader),
new ModelTexture(loader.loadTexture("stallTexture")));
TexturedModel grass = new TexturedModel(OBJLoader.loadObjModel("grassModel", loader),
new ModelTexture(loader.loadTexture("grassTexture")));
TexturedModel playerModel = new TexturedModel(OBJLoader.loadObjModel("person", loader),
new ModelTexture(loader.loadTexture("playerTexture")));
grass.getTexture().setUseFakeLighting(true);
grass.getTexture().setHasTransparency(true);
fern.getTexture().setUseFakeLighting(true);
fern.getTexture().setHasTransparency(true);
stall.getTexture().setShineDamper(10);
stall.getTexture().setReflectivity(1);
tree1.getTexture().setShineDamper(10);
Light light = new Light(new Vector3f(0, 20000, 20000), new Vector3f(1,1,1));
Terrain terrain = new Terrain(0, 0, loader, texturePack, blendMap, "heightMap");
List<Entity> entities = new ArrayList<Entity>();
Random random = new Random();
for (int i = 0; i < 400; i++) {
if (i % 2 == 0) {
float x = random.nextFloat() * 800;
float z = random.nextFloat() * 600;
float y = terrain.getHeightOfTerrain(x, z);
entities.add(new Entity(fern, random.nextInt(4), new Vector3f(x, y, z), 0, random.nextFloat() * 360, 0, 0.9f));
}
if (i % 5 == 0) {
float x = random.nextFloat() * 800;
float z = random.nextFloat() * 600;
float y = terrain.getHeightOfTerrain(x, z);
entities.add(new Entity(tree1, new Vector3f(x, y, z), 0, random.nextFloat() * 360, 0, random.nextFloat() * 1 + 4));
x = random.nextFloat() * 800;
z = random.nextFloat() * 600;
y = terrain.getHeightOfTerrain(x, z);
entities.add(new Entity(tree2, new Vector3f(x, y, z), 0, random.nextFloat() * 360, 0, random.nextFloat() * 0.1f + 0.6f));
}
if (i % 4 == 0) {
float x = random.nextFloat() * 800;
float z = random.nextFloat() * 600;
float y = terrain.getHeightOfTerrain(x, z);
entities.add(new Entity(grass, new Vector3f(x, y, z), 0, 0, 0, 1.5f));
x = random.nextFloat() * 800;
z = random.nextFloat() * 600;
y = terrain.getHeightOfTerrain(x, z);
entities.add(new Entity(flower, new Vector3f(x, y, z), 0, 0, 0, 1.5f));
}
}
MasterRenderer renderer = new MasterRenderer();
Player.parsePlayerData();
float terrainHeight = Player.getTerrainHeight(terrain, Player.PLAYER_X, Player.PLAYER_Z);
Player player = new Player(playerModel, new Vector3f(Player.PLAYER_X, terrainHeight, Player.PLAYER_Z), 0, 0, 0, 1);
camera = new Camera(player);
while (!Display.isCloseRequested()) {
camera.move();
player.move(terrain);
renderer.processEntity(player);
renderer.processTerrain(terrain);
for(Entity entity : entities) {
renderer.processEntity(entity);
}
renderer.render(light, camera);
DisplayManager.updateDisplay();
keyBindings.run();
}
renderer.cleanUp();
loader.cleanUp();
Player.savePlayerData(player/*new Vector3f(player.getPosition().x, terrainHeight, player.getPosition().z)*/);
DisplayManager.closeDisplay();
}
}
Once you're done rendering your 3D scene with perspective projection, you switch to orthographic projection and render your 2D graphics on top of everything else. In your case Screen class would be a good fit for UI rendering.
Game.render(); //Set Persp Proj; Render 3D world (terrain, meshes & models)
Screen.render(); //Set Orhto Proj; Render UI elements on top (textures, fonts)
Really the idea is quite simple, the hard part dwells within the implementation details of your OpenGL version and programming language.
ok so I just started getting into 3D game programming I have a basic world where I have my own physics and basic controls however ever time I factor in speed for my movement it throws off my direction calculations and I don't know how to fix this
here is my camera class
package org.phin.platformer3d.game;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;
import org.phin.platformer3d.lib.Strings;
import org.phin.platformer3d.object.GameObject;
public class Camera extends GameObject {
/**
* the field of view angle
*/
private float fovAngle;
/**
* the ratio between points on a object
*/
private float aspectRatio;
/**
* nearest clipping point
* (the near render distance so objects are not rendered into the camera
*/
private float near;
/**
* farthest clipping point (render distance)
*/
private float far;
private float amtJumped;
private boolean blockKeyUp = false;
private boolean blockKeyDown = false;
/**
* initializes the <code>field of view angle, aspect ratio, near view clipping and
* far clipping (render distance) </code>
*
* #param fovAngle
* #param ar
* #param near
* #param far
*
*/
public Camera(float fovAngle, float ar, float near, float far) {
this.fovAngle = fovAngle;
this.aspectRatio = ar;
this.near = near;
this.far = far;
this.initGL();
}
/**
* Initializes openGL
*/
private void initGL() {
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GLU.gluPerspective(this.fovAngle, this.aspectRatio, this.near, this.far);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glEnable(GL11.GL_TEXTURE_2D);
}
/**
* creates and updates the camera view (called every frame)
*/
public void updateView() {
GL11.glRotatef(super.getRotX(), super.getX(), 0, 0);
GL11.glRotatef(super.getRotY(), 0, super.getY(), 0);
GL11.glRotatef(super.getRotZ(), 0, 0, super.getZ());
GL11.glTranslatef(super.getX(), super.getY(), super.getZ());
}
public void setAmtJumped(float amt) {
this.amtJumped = amt;
}
public void setKeyBlocked(String key, boolean b) {
if (key.equals("up")) {
this.blockKeyUp = b;
} else if (key.equals("down")) {
this.blockKeyDown = b;
}
}
/**
* translates the camera based on the user key input
*/
private void keyEvent() {
if (Keyboard.isKeyDown(Keyboard.KEY_W)) {
if (!this.blockKeyUp) {
this.blockKeyDown = false;
super.setX(super.getX() - (float) Math.cos(Math.toRadians(super.getRotY() + 90)));
super.setZ(super.getZ() + (float) Math.sin(Math.toRadians(super.getRotY() + 90)));
}
} else if (Keyboard.isKeyDown(Keyboard.KEY_S)) {
if (!this.blockKeyDown) {
this.blockKeyUp = false;
super.setX(super.getX() + (float) Math.cos(Math.toRadians(super.getRotY() + 90)));
super.setZ(super.getZ() - (float) Math.sin(Math.toRadians(super.getRotY() + 90)));
}
}
// rotate left or right
if (Keyboard.isKeyDown(Keyboard.KEY_D)) {
this.blockKeyUp = false;
this.blockKeyDown = false;
super.setRotY(super.getRotY() - Strings.SENSITIVITY);
} else if (Keyboard.isKeyDown(Keyboard.KEY_A)) {
this.blockKeyDown = false;
this.blockKeyUp = false;
super.setRotY(super.getRotY() + Strings.SENSITIVITY);
}
// Strife left or right
if (Keyboard.isKeyDown(Keyboard.KEY_E)) {
super.setX(super.getX() - (float) Math.cos(Math.toRadians(super.getRotY())));
super.setZ(super.getZ() + (float) Math.sin(Math.toRadians(super.getRotY())));
} else if (Keyboard.isKeyDown(Keyboard.KEY_Q)) {
super.setX(super.getX() - (float) Math.cos(Math.toRadians(super.getRotY() + 180)));
super.setZ(super.getZ() + (float) Math.sin(Math.toRadians(super.getRotY() + 180)));
}
if (Keyboard.isKeyDown(Keyboard.KEY_SPACE)) {
this.blockKeyDown = false;
this.blockKeyUp = false;
if (this.amtJumped < Strings.JUMP_HEIGHT - super.getHeight()) {
super.setY(super.getY() - 2.5F); // 2.5
this.amtJumped += 2.5F;
} else {
this.amtJumped = 10000;
}
}
}
public void update() {
this.keyEvent();
// camera gravity
super.setY(super.getY() + Strings.GRAVITY);
this.updateView();
}
// no need to render the camera
public void render() {}
}
the occurrences of
super.setX(super.getX() - (float) Math.cos(Math.toRadians(super.getRotY())));
super.setZ(super.getZ() + (float) Math.sin(Math.toRadians(super.getRotY())));
are where I need to add the speed but when I do it throws of the calculation. How can I add speed without throwing it off?
You need to multiply your direction by your speed, not add as i'm guessing your doing now. try this:
super.setX(super.getX() - (float) (speed*Math.cos(Math.toRadians(super.getRotY()))));
super.setZ(super.getZ() + (float) (speed*Math.sin(Math.toRadians(super.getRotY()))));
Can anyone help, my app does not seem to do the onDraw() in the GraView class, even if .invalidate is called upon from either inside or outside the class. I managed to figure out with system.err that it does invalidate the view, however it never gets in the onDraw( ), even though the rest of the app keeps running. I found a lot of solutionssuggesting putting setWillNotDraw(false) in the constructor, but that did not solve anything.
GravIO.java File:
package dabawi.gravitas;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
public class GravIO extends Activity implements Runnable, OnTouchListener {
public final static int clock = 1000;
private GravEngine engine;
private GraView TV;
private SensorManager mSensorManager;
private Sensor mSensor;
private Thread t1;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
t1 = new Thread(this);
t1.start();
engine = new GravEngine();
TV = new GraView(this, engine);
setContentView(TV);
TV.setOnTouchListener(this);
TV.setVisibility(View.VISIBLE);
//mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
System.err.println("Starting Engine") ;
run();
}
#Override
public void run() {
while (true) {
try {
System.err.println("Tik") ;
engine.tick();
TV.invalidate();
Thread.sleep(GravIO.clock);
} catch (InterruptedException ex) {
System.err.println("faal");
}
}
}
#Override
public boolean onTouch(View view, MotionEvent event) {
engine.switchGravity();
return true;
}
}
GraView.java File:
package dabawi.gravitas;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
#SuppressLint({ "DrawAllocation", "ViewConstructor" })
public class GraView extends View {
private GravEngine engine;
private int screenWidth, screenHeight, ySpace = 5, xSpace, scale;
private Paint paint;
private int xLoc, yLoc;
private boolean xWall = false, yWall = false;
public GraView(Context context, GravEngine engine) {
super(context);
setWillNotDraw(false);
this.engine = engine;
calcScale(context);
}
#Override // We think the problem is with this method, that it is never called upon.
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
System.err.println("Calculating position");
calcPos();
canvas = new Canvas();
// drawing background
paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
canvas.drawPaint(paint);
drawGame(canvas);
}
private void drawGame(Canvas canvas) {
drawRoom(canvas);
drawPlayer(canvas);
}
#SuppressWarnings("deprecation")
private void calcScale(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
screenWidth = d.getWidth();
screenHeight = d.getHeight();
scale = screenHeight / ySpace;
xSpace = screenWidth / scale;
}
private void calcPos() {
xLoc = (engine.getxPlayer() / GravEngine.roomScaling);
yLoc = (engine.getyPlayer() / GravEngine.roomScaling);
if (xLoc < (xSpace + 1) / 2) {
xLoc = (xSpace + 1) / 2;
xWall = true;
} else if (xLoc > (GravRoom.xSize - ((xSpace + 1) / 2))) {
xLoc = GravRoom.xSize - ((xSpace + 1) / 2);
xWall = true;
} else {
xWall = false;
}
if (yLoc < (ySpace + 1) / 2) {
yLoc = (ySpace + 1) / 2;
yWall = true;
} else if (yLoc > (GravRoom.xSize - ((ySpace + 1) / 2))) {
xLoc = GravRoom.ySize - ((ySpace + 1) / 2);
yWall = true;
} else {
yWall = false;
}
}
private void drawPlayer(Canvas canvas) {
float xPos = engine.getxPlayer() / GravEngine.roomScaling, yPos = engine
.getyPlayer() / GravEngine.roomScaling;
if (xWall) {
}
if (yWall) {
}
paint.setColor(Color.BLUE);
int left = (int) (xPos * scale), top = (int) (yPos * scale);
int right = left + (GravEngine.pxSize / GravEngine.roomScaling) * scale;
int bot = top + (GravEngine.pySize / GravEngine.roomScaling) * scale;
canvas.drawRect(left, top, right, bot, paint);
}
private void drawRoom(Canvas canvas) {
for (int i = 0, x = xLoc - ((xSpace + 1) / 2); i < xSpace + 1; x++, i++) {
for (int j = 0, y = yLoc - ((ySpace + 1) / 2); i < ySpace + 1; y++, j++) {
drawRoomPart(x,y,i,j,canvas);
}
}
}
private void drawRoomPart(int x, int y, int i, int j, Canvas canvas) {
if (x >= 0 && y >= 0 && x < GravRoom.xSize && y < GravRoom.ySize) {
short type = engine.getRoom(engine.getCurrentRoom()).getGridPos(x,y);
if (type != 0) {
drawBlock(canvas, i, x, j, y, type);
}
}
}
private void drawBlock(Canvas canvas, int i, int x, int j, int y, short type) {
int left = i * scale, top = y * scale;
int right = left + scale;
int bot = top + scale;
paint.setColor(colorBlock(type));
canvas.drawRect(left, top, right, bot, paint);
System.err.println("Left" + left + " top: " + top + " right: "
+ right + " bot: " + bot);
}
private int colorBlock(short type) {
if (type == 1) {
return Color.DKGRAY;
} else if (type == 2) {
return Color.CYAN;
} else if (type == 3) {
return Color.GREEN;
} else if (type == 4) {
return Color.RED;
} else {
return Color.MAGENTA;
}
}
// private void imageBlock(short type) {
//
// }
}
Ouch !
Your call to your run method is executed in the UIThread (as the onCreate method), and it's doing an infinite loop in it.
Just add a println after the call and you will see that the UI thread is never released, your application should not even start !
You don't see any changes because you are creating a new canvas and drawing on that. To fix this, remove the line
canvas = new Canvas();
Also, you should initiate your Paint outside of the onDraw method (this is an optimization recommended by the Android documentation).