I found an adaptation of ARToolKit + jpct + android:
https://github.com/plattysoft/ArToolKitJpctBaseLib
I've got draw various 3D objects on the screen.
But now I have the problem: I need to touch them
I saw this tutorial: http://www.jpct.net/wiki/index.php?title=Picking
But my class is something different, is very abstracted and simple and I'm a newbie ..
This is the mainClass, I don't found my framebuffer...
import android.os.Bundle;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.Toast;
import com.threed.jpct.Loader;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import org.artoolkit.ar.jpct.ArJpctActivity;
import org.artoolkit.ar.jpct.TrackableLight;
import org.artoolkit.ar.jpct.TrackableObject3d;
import java.io.IOException;
import java.util.List;
public class RealidadAumentada extends ArJpctActivity{
private Object3D astronauta = null;
private TrackableObject3d cubo = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
/**
* Use the FrameLayout in this Activity's UI.
*/
#Override
protected FrameLayout supplyFrameLayout() {
return (FrameLayout)this.findViewById(R.id.mainLayout);
}
public void configureWorld(World world) {
world.setAmbientLight(150, 150, 150);
}
protected void populateTrackableObjects(List<TrackableObject3d> list) {
Object3D astronauta2 = null;
try {
cubo = new TrackableObject3d("single;Data/patt.hiro;80", getCube());
//astronauta2 = getAstronauta2());
astronauta = getAstronauta();
astronauta.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
} catch (IOException e) {
e.printStackTrace();
}
TrackableLight light = new TrackableLight();
light.setIntensity(0, 0, 255);
light.setPosition(new SimpleVector(0, 0, 100));
cubo.addLight(light);
cubo.addChild(astronauta);
list.add(cubo);
}
private Object3D getCube() throws IOException {
int scale = 40;
Object3D object3D = Primitives.getCube(scale);
// Cubes in jpct are rotated by 45 degrees when created.
object3D.rotateY((float) Math.PI / 4);
object3D.setOrigin(new SimpleVector(0, 0, scale));
return object3D;
}
private Object3D getAstronauta() throws IOException {
int scale = 40;
Object3D[] astronaut = Loader.load3DS(getAssets().open("astronaut1.3ds"), 5);
astronaut[0].setOrigin(new SimpleVector(0, 0, 270));
return astronaut[0];
}
This method doesnt work
public boolean onTouchEvent(MotionEvent me) {
if (me.getAction() == MotionEvent.ACTION_DOWN) {
Toast.makeText(this, cubo.getXAxis().toString()+" "+String.valueOf(me.getX()),2000).show();
// Toast.makeText(this,String.valueOf(cubo.getCenter()),2000).show();
return true;
}
....
}
Solved !
I spent many hours but I finally got what I wanted.
Draw several 3D objects on a ARToolKit(Android) marker and then click on each of them.
Thanks for the help
This is my solution:
patron = new TrackableObject3d("single;Data/patt.hiro;80");
Patron is a trackable object, is the example patt hiro.
objeto.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
patron.addChild(objeto);
if (mWorld.getObjectByName(objeto.getName())==null)
mWorld.addObject(objeto);
patron.addChild because I have many objects in the screen.
objeto.setCollisionMode is a jcpt function that makes the object collisionable.
The next step: Touch screen (more info in internet)
public boolean onTouch(View v, MotionEvent event) {
Next step:
fb is the frameBuffer. xpos and ypos are the 2Dcoordinates. Then,
You have to draw a raytrace from xpos and ypos to get the 3D coordinates.
objeto is the object you're touching.
case MotionEvent.ACTION_UP:
int xpos = (int) event.getX();
int ypos = (int) event.getY();
SimpleVector dir = Interact2D.reproject2D3DWS(mWorld.getCamera(), fb, xpos, ypos);
SimpleVector norm = dir.normalize();
Object[] res = mWorld.calcMinDistanceAndObject3D(mWorld.getCamera().getPosition(), norm, 1000);
Object3D objeto = (Object3D) res[1];
float f = mWorld.calcMinDistance(mWorld.getCamera().getPosition(), norm, 1000);
if (f != Object3D.COLLISION_NONE) {
//Interact with object
String nombre = objeto.getName();
Vibrator vib = (Vibrator) getSystemService(VIBRATOR_SERVICE);
vib.vibrate(100);
}
I don't see you setting the touch listener anywhere, overriding that method works on the GLSurfaceView class, not on the Activity.
You could set a touch listener to the frame layout (R.id.mainLayout) on creation after setting the content view.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.mainLayout).setOnTouchListenr(this);
}
#Override
public onTouch(View v, MotionEvent event) {
// Your implementation of touch goes here, not in onTouchEvent
}
The whole idea of the library you are using is to encapsulate all the boilerplate code, such as creating a Renderer which is going to be the same for almost every app.
If you want to access the SurfaceView and extend it to implement that method there, you can do it overwriting this part: https://github.com/plattysoft/ArToolKitJpctBaseLib/blob/master/ArJpctBaseLib/src/main/java/org/artoolkit/ar/base/ARActivity.java#L217
Related
For my university thesis, I need a android program which can detect and recognize a face in real time. I have read about 'android-vision' library and tested the example code.
https://github.com/googlesamples/android-vision/tree/master/visionSamples/FaceTracker/app/src/main/java/com/google/android/gms/samples/vision/face/facetracker.
Modified code:
package com.google.android.gms.samples.vision.face.facetracker;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.AsyncTask;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.samples.vision.face.facetracker.ui.camera.GraphicOverlay;
import com.google.android.gms.vision.face.Face;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Graphic instance for rendering face position, orientation, and landmarks within an associated
* graphic overlay view.
*/
class FaceGraphic extends GraphicOverlay.Graphic
{
private static final float FACE_POSITION_RADIUS = 10.0f;
private static final float ID_TEXT_SIZE = 40.0f;
private static final float ID_Y_OFFSET = 50.0f;
private static final float ID_X_OFFSET = -50.0f;
private static final float BOX_STROKE_WIDTH = 5.0f;
public Canvas canvas1;
public Face face;
int i =0;
int flag = 0;
private static final int COLOR_CHOICES[] = {
Color.BLUE,
Color.CYAN,
Color.GREEN,
Color.MAGENTA,
Color.RED,
Color.WHITE,
Color.YELLOW
};
private static int mCurrentColorIndex = 0;
private Paint mFacePositionPaint;
private Paint mIdPaint;
private Paint mBoxPaint;
private volatile Face mFace;
private int mFaceId;
private float mFaceHappiness;
public Bitmap myBitmap ;
FaceGraphic(GraphicOverlay overlay)
{
super(overlay);
mCurrentColorIndex = (mCurrentColorIndex + 1) % COLOR_CHOICES.length;
final int selectedColor = COLOR_CHOICES[mCurrentColorIndex];
mFacePositionPaint = new Paint();
mFacePositionPaint.setColor(selectedColor);
mIdPaint = new Paint();
mIdPaint.setColor(selectedColor);
mIdPaint.setTextSize(ID_TEXT_SIZE);
mBoxPaint = new Paint();
mBoxPaint.setColor(selectedColor);
mBoxPaint.setStyle(Paint.Style.STROKE);
mBoxPaint.setStrokeWidth(BOX_STROKE_WIDTH);
}
void setId(int id)
{
mFaceId = id;
flag = 1;
}
/**
* Updates the face instance from the detection of the most recent frame. Invalidates the
* relevant portions of the overlay to trigger a redraw.
*/
void updateFace(Face face)
{
mFace = face;
postInvalidate();
}
/**
* Draws the face annotations for position on the supplied canvas.
*/
#Override
public void draw(Canvas canvas)
{
face = mFace;
if (face == null)
{
return;
}
// Draws a circle at the position of the detected face, with the face's track id below.
float x = translateX(face.getPosition().x + face.getWidth() / 2);
float y = translateY(face.getPosition().y + face.getHeight() / 2);
// canvas.drawCircle(x, y, FACE_POSITION_RADIUS, mFacePositionPaint);
canvas.drawText("id: " + mFaceId, x + ID_X_OFFSET, y + ID_Y_OFFSET, mIdPaint);
// canvas.drawText("happiness: " + String.format("%.2f", face.getIsSmilingProbability()), x - ID_X_OFFSET, y - ID_Y_OFFSET, mIdPaint);
// canvas.drawText("right eye: " + String.format("%.2f", face.getIsRightEyeOpenProbability()), x + ID_X_OFFSET * 2, y + ID_Y_OFFSET * 2, mIdPaint);
// canvas.drawText("left eye: " + String.format("%.2f", face.getIsLeftEyeOpenProbability()), x - ID_X_OFFSET*2, y - ID_Y_OFFSET*2, mIdPaint);
// Draws a bounding box around the face.
float xOffset = scaleX(face.getWidth() / 2.0f);
float yOffset = scaleY(face.getHeight() / 2.0f);
float left = x - xOffset;
float top = y - yOffset;
float right = x + xOffset;
float bottom = y + yOffset;
canvas.drawRect(left, top, right, bottom, mBoxPaint);
Log.d("MyTag", "hello "+i);
i++;
if (flag == 1)
{
flag = 0;
canvas1=canvas;
// send face image to server for recognition
new MyAsyncTask().execute("ppppp");
}
}
class MyAsyncTask extends AsyncTask<String, Void, String>
{
private Context context;
public MyAsyncTask()
{
// TODO Auto-generated constructor stub
//context = applicationContext;
}
protected String doInBackground(String... params)
{
try
{
Log.d("MyTag", "face.getWidth() "+face.getWidth());
Bitmap temp_bitmap = Bitmap.createBitmap((int)face.getWidth(), (int)face.getHeight(), Bitmap.Config.RGB_565);
canvas1.setBitmap(temp_bitmap);
}
catch (Exception e)
{
Log.e("MyTag", "I got an error", e);
e.printStackTrace();
}
Log.d("MyTag", "doInBackground");
return null;
}
protected void onPostExecute(String result) {
Log.d("MyTag", "onPostExecute " + result);
// tv2.setText(s);
}
}
}
It give me this error:
12-16 03:08:00.310 22926-23044/com.google.android.gms.samples.vision.face.facetracker E/MyTag: I got an error
java.lang.UnsupportedOperationException
at android.view.HardwareCanvas.setBitmap(HardwareCanvas.java:39)
at com.google.android.gms.samples.vision.face.facetracker.FaceGraphic$MyAsyncTask.doInBackground(FaceGraphic.java:175)
at com.google.android.gms.samples.vision.face.facetracker.FaceGraphic$MyAsyncTask.doInBackground(FaceGraphic.java:158)
This code can detect face in real time. For recognition part, I am planning to use 'JavaCV' https://github.com/bytedeco/javacv. If I can capture the face in a bitmap then I can save it in .jpg image then I can recognize it. Could you please give me some advise, how to save detected face. Thank you.
TL;DR: Capture a Frame, process it, then save/export.
From the source
#Override
public void setBitmap(Bitmap bitmap) {
throw new UnsupportedOperationException();
}
This means that the Canvas cannot handle the setBitmap(Bitmap bitmap) method
You have several issues with what you are performing.
First: Loads of AsynkTask(s), and many are usless/redundand
If you are using the com.google.android.gms.vision.* classes, then you are likely receiveing around 30 events per second. When an event occurs, the captured Frame is almost assured to be different from the one evaluated. You are racing against your conditions.
Second: Using Canvas to set Bitmap
Always, when using a Class, check its documentation and ancestors and finally its implementation.
An ImageView would perform as you desire. By receiving a Bitmap, then setting to it. All racing conditions would be handled by the OS< and redundant requests would be dropped by the Main Looper
Finally
If what you need is perhaps "Take a picture, when someone is smiling with eyes closed", then you need to inverse your logic. Use a source to generate Frame(s). Then process the Frame, and if it meets your criteria, save it.
This codelabs project does almost what you want, and it explains its details very well
I am using Handler post delay to call onDraw each time I want to draw new rectangle, but for every new rectangle erase the previous one ..
How can I make the canvas keep the content of all rectangles:
My code:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.CountDownTimer;
import android.os.Handler;
import android.util.Log;
import com.adhamenaya.microchart.model.ChartData;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
/**
* Created by Admin on 18/12/2016.
*/
public class ColumnChart extends Chart implements Runnable {
private int mSpace = 0;
private int mColumnSize = 0;
private int mColumnsCount = 0;
private int mCurrentStart = 0;
private float mHeightUnit = 0;
private int mHeightDiff;
int columnIndex = 0;
private Handler mHandler;
private Canvas mCanvas;
private Iterator mDataIterator;
static final long FRAME_TIME = 100;
private ArrayList<Rect> rectangles = new ArrayList<Rect>();
public ColumnChart(Context context) {
super(context);
mHandler = new Handler();
}
#Override
protected void prepare() {
if (mChartData != null && mChartData.getSingleData().size() > 0) {
mColumnsCount = mChartData.getSingleData().size();
// Column size, 1 is added to reserve a space at the end of the chart
mColumnSize = (int) ((mWidth / (mColumnsCount)) * 0.9);
// Calculate the space between the bars
mSpace = (mWidth / mColumnsCount) - mColumnSize;
// Calculate height unit
// Calculate 80% of the total height
float height08 = mHeight * 0.8f;
mHeightUnit = height08 / mChartData.getMax();
// Draw bars
mDataIterator = mChartData.getSingleData().entrySet().iterator();
mMainPaint = getRectPaint();
// Create rect objects
while (mDataIterator.hasNext()) {
Map.Entry entry = (Map.Entry) mDataIterator.next();
int columnHeight = (int) ((int) entry.getValue() * mHeightUnit);
String key = (String) entry.getKey();
// Shift the
mCurrentStart += mSpace;
// Calculate the difference between the total height and the height of the column
mHeightDiff = mHeight - columnHeight;
mCurrentStart += mColumnSize;
mDataIterator.remove();
Rect rect = new Rect(mCurrentStart, mHeightDiff,
mCurrentStart + mColumnSize, mHeight);
rectangles.add(rect);
}
}
}
#Override
protected void paintChart(Canvas canvas) {
}
#Override
public void setData(ChartData data) {
this.mChartData = data;
prepare();
mHandler.post(this);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Get measured height and width of the view
setMeasuredDimension(getMeasurement(widthMeasureSpec, mWidth),
getMeasurement(heightMeasureSpec, mHeight));
// mWidth = MeasureSpec.getSize(widthMeasureSpec);
// mHeight = MeasureSpec.getSize(heightMeasureSpec);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(columnIndex > 0 && columnIndex<rectangles.size())
canvas.drawRect(rectangles.get(columnIndex), getRectPaint());
}
#Override
public void run() {
if(columnIndex<rectangles.size()){
invalidate();
columnIndex++;
mHandler.postDelayed(this,FRAME_TIME);
}else{
mHandler.removeCallbacks(this);
}
}
}
Create a FrameLayout on which you want to draw rectangles. Create a view every time you are drawing a new circle. Draw circle on newly created view and the add that view to FrameLayout. Background of the view will be transparent by default. If not then set the background as transparent. This way your previous rectangles will be visible and new rectangle will be drawn on existing rectangles.
Your are near to make it done! Just call you prepare after calling invalidate method.
#Override
public void run() {
if(columnIndex<rectangles.size()){
invalidate();
columnIndex++;
mHandler.postDelayed(this,FRAME_TIME);
}else{
mHandler.removeCallbacks(this);
eraseAll();
}
}
...
public void eraseAll() {
this.canvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
prepare();
}
For me this logic is working fine
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(columnIndex < rectangles.size()) {
for (int i = 0; i <= columnIndex; ++i) {
canvas.drawRect(rectangles.get(i), paint);
}
}
}
Simplest heck is to keep the canvas object as class level variable and always draw on this canvas object and in super.onDraw() pass on this canvas, it will always keep your previous rectangles drawn
I want to make a sprite\bitmap jump using only android (no game engines). I wasn't able to find tutorials on how to do so in android using only canvas and views, but I did find a tutorial for xna(http://www.xnadevelopment.com/tutorials/thewizardjumping/thewizardjumping.shtml), and I tried to recreate it with the tools android offers. I was able to make the character move left and right using the tutorial code but making it jump just won't work.
this is my sprite class:
package com.example.spiceup;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.view.KeyEvent;
import android.widget.Toast;
public class Sprite {
enum State
{
Walking, Standing, Jumping
}
State mCurrentState = State.Standing;
Point mDirection;
int mSpeed = 0;
Context cc;
int mPreviousKeyboardState;
private String spriteName;
Bitmap sprite;
private int rows;
private int rows2;
int START_POSITION_X = 125;
int START_POSITION_Y = 245;
int SPRITE_SPEED = 6;
int MOVE_UP = -1;
int MOVE_DOWN = 1;
int MOVE_LEFT = -1;
int MOVE_RIGHT = 1;
Point mStartingPosition;
int aCurrentKeyboardState;
private float mScale = 1.0f;
Point Position;
public Sprite(String name,Bitmap sprite) {
this.sprite=sprite;
this.spriteName=name;
Position=new Point(150,150);
mStartingPosition=new Point(150,150);
mDirection=new Point(0,0);
}
public void Update()
{
UpdateMovement(aCurrentKeyboardState);
UpdateJump(aCurrentKeyboardState);
}
public void setkeyboard(int keyboard){
aCurrentKeyboardState = keyboard;
}
public void setLastKeyboard(int keyboard){
mPreviousKeyboardState = keyboard;
}
private void UpdateMovement(int aCurrentKeyboardState)
{
if (mCurrentState == State.Walking)
{
mSpeed = 0;
mDirection.x = 0;
if (aCurrentKeyboardState==KeyEvent.KEYCODE_A)
{
mSpeed = SPRITE_SPEED;
mDirection.x = MOVE_LEFT;
}
else if(aCurrentKeyboardState==KeyEvent.KEYCODE_D)
{
mSpeed = SPRITE_SPEED;
mDirection.x= MOVE_RIGHT;
}
Position.x += mDirection.x * mSpeed;
}
}
private void UpdateJump(int aCurrentKeyboardState)
{
if (mCurrentState == State.Walking)
{
if (aCurrentKeyboardState==KeyEvent.KEYCODE_SPACE && mPreviousKeyboardState!=KeyEvent.KEYCODE_SPACE)
{
Jump();
}
}
if (mCurrentState == State.Jumping)
{
if (mStartingPosition.y - Position.y> 150)
{
Position.y += mDirection.y * mSpeed;
mDirection.y = MOVE_DOWN;
}
if (Position.y > mStartingPosition.y)
{
Position.y = mStartingPosition.y;
mCurrentState = State.Walking;
}
}
}
private void Jump()
{
if (mCurrentState != State.Jumping)
{
mCurrentState = State.Jumping;
mStartingPosition = Position;
mDirection.y = MOVE_UP;
mSpeed = 6;
Position.y += mDirection.y * mSpeed;
}
}
public void Draw(Canvas c)
{
c.drawBitmap(sprite, Position.x,Position.y, null);
}
public void setmCurrentState(State mCurrentState) {
this.mCurrentState = mCurrentState;
}
}
this is the surfaceview:
import com.example.spiceup.Sprite.State;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameView extends SurfaceView {
Context cc;
Bitmap Sprite;
Sprite sprite2;
Handler handlerAnimation100;
private GameLoopThread gameLoopThread;
private SurfaceHolder holder;
public GameView(Context c) {
// TODO Auto-generated constructor stub
super(c);
gameLoopThread = new GameLoopThread(this);
this.cc=c;
this.Sprite=BitmapFactory.decodeResource(getResources(), R.drawable.walk1);
this.Sprite=Bitmap.createScaledBitmap(Sprite, Sprite.getWidth()*2, Sprite.getHeight()*2, false);
sprite2=new Sprite("Spicy",Sprite);
this.requestFocus();
this.setFocusableInTouchMode(true);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
gameLoopThread.setRunning(false);
while (retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.BLACK);
sprite2.Update();
sprite2.Draw(canvas);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
sprite2.setkeyboard(keyCode);
sprite2.setmCurrentState(State.Walking);
return false;
}
#Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
sprite2.setmCurrentState(State.Standing);
sprite2.setLastKeyboard(keyCode);
return false;
}
}
if anyone knows where is my error or has a better code to show me I'll be happy, all I'm trying to do is to create a bitmap that moves around and can jump (but also jump while walking)
So I think what is happening in your code is that it's hitting the max height in the game loop and adding back to the y of the sprite. Second game loop run it is no longer above or near the max height distance therefore you stop going down and your start position becomes that position in the air. On a third loop through you hit spacebar again and your sprite starts the whole jumping processes over and the same thing happens on the next to loops through or however many it takes to trigger that if statement to get the sprite to start falling.
Good place to start is have a persistent boolean that determines whether or not the sprite is actually done climbing and jumping state should stay true while climbing and falling. See below.
boolean maxJumpAchieved = false;
if (mCurrentState == State.Jumping)
{
if (mStartingPosition.y - Position.y> 150)
{
maxJumpAchieved = true;
}
if (maxJumpAchieved) {
mDirection.y = MOVE_DOWN;
Position.y += mDirection.y * mSpeed;
}
if (Position.y > mStartingPosition.y)
{
maxJumpAchieved = false;
Position.y = mStartingPosition.y;
mCurrentState = State.Walking;
}
}
I think this should get you in the right direction but if you have issues let me know and I can edit my answer.
Another thing to note is don't set the mCurrentState to State.Walking until you know for sure you're on the ground otherwise you could double jump for days.
I have been researching and struggling with my code to get a textview to update the score when a "ghost" is touched.
This is my first Android application and so far as i can tell(i added Log.w() to the ontouch but a log is never posted as well as the score not being incremented or even appearing) the onTouch(View v, MotionEvent event) is never called. Below is my code.
package com.cs461.Ian;
//TODO:Add accelerometer support
//TODO:Add Clickable ghosts
//TODO:Add camera background
/*Completed:(As of 2:30am 4/16)
* Activity launches
* Ghost appears on screen
* Ghost will randomly move around the screen
*/
import java.util.Random;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.widget.TextView;
public class CameraActivity extends Activity{
Bitmap g;
Ghost a;
Ghost still;
SurfaceHolder mSurfaceHolder;
boolean firsttime=true;
int draw_x,draw_y,xSpeed,ySpeed,score=0;
TextView t;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game);
a = new Ghost(getApplicationContext());
still = new Ghost(getApplicationContext());
//requestWindowFeature(Window.FEATURE_NO_TITLE);
a.Initalize(BitmapFactory.decodeResource(getResources(), R.drawable.ghost), 20, 20);
still.Initalize(BitmapFactory.decodeResource(getResources(), R.drawable.ghost), 120, 120);
t = (TextView) findViewById(R.id.t);
t.setText("TEST SCORE TO SEE IF TEXTVIEW SHOWS UP");
a.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN){
score++;
t.setText("Score: "+score);
}
return true;
}
});
still.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN){
score++;
t.setText("Score: "+score);
Log.w("CLICKED","Clicked on ghost "+score+" times");
}
return true;
}
});
setContentView(new Panel(this));
}
class Panel extends View {
public Panel(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
//g.Initalise(BitmapFactory.decodeFile("/res/drawable-hdpi/ghost.png"), 200, 150, 5, 5);;
update(canvas);
invalidate();
}
/*Places ghost on screen and bounces it around in the screen. My phone is apparently only API level 4(the most up to date is 15) so i didn't code it
*for the accelerometer yet.
*/
public void update(Canvas canvas) {
Random rand = new Random();
if(firsttime){
draw_x = Math.round(System.currentTimeMillis() % (this.getWidth()*2)) ;
draw_y = Math.round(System.currentTimeMillis() % (this.getHeight()*2)) ;
xSpeed = rand.nextInt(10);
ySpeed = rand.nextInt(10);
firsttime=false;
}
draw_x+=xSpeed;
draw_y+=ySpeed;
draw_x = Math.round(System.currentTimeMillis() % (this.getWidth()*2)) ;
draw_y = Math.round(System.currentTimeMillis() % (this.getHeight()*2)) ;
if (draw_x>this.getWidth()){
draw_x = (this.getWidth()*2)-draw_x;
xSpeed = rand.nextInt(10);
if(xSpeed >=5)
xSpeed=-xSpeed;
}
if (draw_y>this.getHeight()){
draw_y = (this.getHeight()*2)-draw_y;
ySpeed = rand.nextInt(10);
if(ySpeed >=5)
ySpeed=-ySpeed;
}
g = BitmapFactory.decodeResource(getResources(), R.drawable.ghost);
canvas.drawBitmap(g, draw_x, draw_y, null);
still.draw(canvas);
a.update(canvas);
}
}
}
Forgot to add class Ghost:
package com.cs461.Ian;
import java.util.Random;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
public class Ghost extends View implements View.OnTouchListener{
public Ghost(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
private Bitmap mAnimation;
private int mXPos;
private int mYPos;
private Rect mSRectangle;
private int mSpriteHeight;
private int mSpriteWidth;
View v;
Rect dest;
int score = 0;
/*public Ghost() {
mSRectangle = new Rect(0,0,0,0);
mXPos = 80;
mYPos = 200;
}*/
public void Initalize(Bitmap theBitmap, int Height, int Width) {
mSRectangle = new Rect(0,0,0,0);
mXPos = 80;
mYPos = 200;
mAnimation = theBitmap;
mSpriteHeight = Height;
mSpriteWidth = Width;
mSRectangle.top = 0;
mSRectangle.bottom = mSpriteHeight;
mSRectangle.left = 0;
mSRectangle.right = mSpriteWidth;
dest = new Rect(mXPos, mYPos, mXPos + mSpriteWidth,
mYPos + mSpriteHeight);
}
public void draw(Canvas canvas) {
canvas.drawBitmap(mAnimation, mXPos, mYPos, null);
}
public void update(Canvas canvas) {
new Random();
mXPos = Math.round(System.currentTimeMillis() % (canvas.getWidth()*2)) ;
mYPos = Math.round(System.currentTimeMillis() % (canvas.getHeight()*2)) ;
if (mXPos>canvas.getWidth())
mXPos = (canvas.getWidth()*2)-mXPos;
if (mYPos>canvas.getHeight())
mYPos = (canvas.getHeight()*2)-mYPos;
draw(canvas);
}
public Rect getRect() {
return mSRectangle;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
score++;
//CameraActivity.t.setText("Score: "+CameraActivity.score);
Log.w("CLICKED","Clicked on ghost "+score+" times");
return true; //doesn't work if returns false either
}
}
Override dispatchTouchEvent(MotionEvent event) in your Activity to handle all the touch events that may occur. Return false to pass down the MotionEvent to the next view\layout in the hierachy if they they handle events.
I have an array of objects that need to be drawn to a canvas; each object is represented as:
scatterPlot.java
package scatter.plot;
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.view.View;
public class scatterPoint extends View {
private final Point coordinates;
private final int itemShape;
private Paint itemColour = new Paint(Paint.ANTI_ALIAS_FLAG);
private scatterPoint[] mShapes;
public scatterPoint(Context context, Point p, int shape, Paint colour) { // Constructor
super(context);
coordinates = p;
itemShape = shape;
itemColour = colour;
}
//get set points
public void setPoints(scatterPoint[] p){
mShapes = p;
}
public scatterPoint[] getScatterPoints(){
return mShapes;
}
#Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
int radius = 10;
for (scatterPoint i : mShapes) {
switch(itemShape){
case 0:
canvas.drawRect(i.coordinates.x - radius, i.coordinates.y - radius, i.coordinates.x + radius, i.coordinates.y + radius, i.itemColour);
break;
case 1:
Path path = new Path();
path.moveTo(i.coordinates.x - radius, i.coordinates.y - radius);
path.lineTo(i.coordinates.x, i.coordinates.y + radius);
path.lineTo(i.coordinates.x + radius, i.coordinates.y - radius);
path.lineTo(i.coordinates.x - radius, i.coordinates.y - radius);
path.close();
canvas.drawPath(path, i.itemColour);
break;
case 2:
canvas.drawCircle(i.coordinates.x, i.coordinates.y, radius, i.itemColour);
break;
}
}
}
public Point getCoordinates(){
return coordinates;
}
public int getShape(){
return itemShape;
}
public Paint getColour(){
return itemColour;
}
}
Relevant methods from main (ScatterPlotActivity.java):
package scatter.plot;
import java.util.Random;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Display;
import android.view.WindowManager;
import android.widget.FrameLayout;
public class ScatterPlotActivity extends Activity {
FrameLayout main;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
main = (FrameLayout) findViewById(R.id.main_view);
scatterPoint[] points = generatePoints();
//
//add scatterPoint to main
//
}
public scatterPoint[] generatePoints(){
//
return points;
}
}
Any ideas on what is wrong with how I'm trying to draw these objects?
I think the problem comes from the fact that you're creating each time a new FrameLayout. Declare your FrameLayout in your main and then call your method drawPoints like this:
drawPoint(points[i], main);
and your method will look like this :
public void drawPoint(scatterPoint point, FrameLayout main) {
main.addView(point);
}
This way they will always be added to the same Layout.
The problem is:
public void drawPoint(scatterPoint point) {
FrameLayout main = (FrameLayout) findViewById(R.id.main_view);
main.addView(point);
}
Make your FrameLayout main; a global variable. Then, right after you call setContentView(R.layout.x); in onActivityCreated(), call main = (FrameLayout) findViewById(R.id.main_view);
You only want to make this call once. Every time the current implementation calls public void drawPoint(scatterPoint point);, the FrameLayout is being reinitialized and clearing all the old drawings.
By the looks of things, you are actually drawing all of your scatter point views. However, due to how you are adding them to the FrameLayout, they are stacking on top of each other. Look in your drawPoint() method. You add the point to FrameLayout, which was designed to only handle one view (for more on this statement refer to FrameLayout), and the FrameLayout just draws the new view right over the last view drawn.
class ScatterShape {
public float mX = 0, mY = 0;
public int mShape = 0;
public Paint mColor = new Paint();
public ScatterShape(float x, float y, int shape, int color) {
mX = x;
mY = y;
mShape = shape;
mColor.setColor(color);
}
}
public class ScatterShaperDrawer extends View {
private List<ScatterShape> mShapes = new ArrayList<ScatterShapes>();
private float mmRadius = 5;
// Make getter and setter
#Override public void onDraw(Canvas canvas) {
for (ScatterShape i : mShapes) {
switch(i.mShape){
case 0:
canvas.drawRect(i.mX - mRadius, i.mY - mRadius, i.mX + mRadius, i.mY + mRadius, itemColor);
break;
case 1:
Path path = new Path();
path.moveTo(i.mX - mRadius, i.mY - mRadius);
path.lineTo(i.mX, i.mY + mRadius);
path.lineTo(i.mX + mRadius, i.mY - mRadius);
path.lineTo(i.mX - mRadius, i.mY - mRadius);
path.close();
canvas.drawPath(path, i.mColor);
break;
case 2:
canvas.drawCircle(i.mX, i.mY, mRadius, i.mColor);
break;
}
}
}
}