So I have got this problem where I do not know how to possible code tile based movement in 4 directions (NSWE) for action script 2.0.
I have this code but it is dynamic movement, which makes the char move in all 8 directions (NW,NE,SW,SE N,S,W,E). The goal is to limit the movements to tile based and in only 4 directions (NSEW)
onClipEvent(enterFrame)
{
speed=5;
if(Key.isDown(Key.RIGHT))
{
this.gotoAndStop(4);
this._x+=speed;
}
if(Key.isDown(Key.LEFT))
{
this.gotoAndStop(3);
this._x-=speed;
}
if(Key.isDown(Key.UP))
{
this.gotoAndStop(1);
this._y-=speed;
}
if(Key.isDown(Key.DOWN))
{
this.gotoAndStop(2);
this._y+=speed;
}
}
The most simple and straightforward way is to move that thing along X-axis OR along Y-axis, only one at a time, not both.
onClipEvent(enterFrame)
{
speed = 5;
dx = 0;
dy = 0;
// Figure out the complete picture of keyboard input.
if (Key.isDown(Key.RIGHT))
{
dx += speed;
}
if (Key.isDown(Key.LEFT))
{
dx -= speed;
}
if (Key.isDown(Key.UP))
{
dy -= speed;
}
if (Key.isDown(Key.DOWN))
{
dy += speed;
}
if (dx != 0)
{
// Move along X-axis if LEFT or RIGHT pressed.
// Ignore if it is none or both of them.
this._x += dx;
if (dx > 0)
{
this.gotoAndStop(4);
}
else
{
this.gotoAndStop(3);
}
}
else if (dy != 0)
{
// Ignore if X-axis motion is already applied.
// Move along Y-axis if UP or DOWN pressed.
// Ignore if it is none or both of them.
this._y += dy;
if (dy > 0)
{
this.gotoAndStop(2);
}
else
{
this.gotoAndStop(1);
}
}
}
Related
Pulling my hair out with this one, hope its not something silly. Below is a snippet of code from a program. When leftwalker.x == 150 he should gotoAndPlay the standstill animation but it only plays the first frame, the previous animation runs fine. Any ideas?
var data =
{
images: ["images/ste_basic_wand.png"],
frames: {width:64, height:64},
animations:
{
// start, end, next, speed
walkright: [143,151,"walkright",1.18],
walkleft: [118,125,"walkleft",1.18],
stand:[39,45,"stand",0.08],
standstill:[26,27, "standstill", 1.2]
}
};
var spriteSheet = new createjs.SpriteSheet(data);
leftwalker = new createjs.Sprite(spriteSheet);
leftwalker.name = "lefty";
leftwalker.framerate = 30;
leftwalker.x = 100;
leftwalker.y = 100;
leftwalker.currentFrame = 0;
leftwalker.scaleY = leftwalker.scaleX = 2;
leftwalker.gotoAndPlay("walkright");
stage.addChild(leftwalker);
createjs.Ticker.setFPS(10);
createjs.Ticker.addEventListener("tick", tick);
}
function tick(event) {
if(container.x < 150)
{
container.x += 5;
}
if(leftwalker.x < 150)
{
leftwalker.x += 2;
}
if(leftwalker.x == 150)
{
leftwalker.gotoAndPlay("standstill");
}
// if (circle.x > stage.canvas.width) { circle.x = 0; }
stage.update(event); // important!!
}
The reason this happens is because you are calling gotoAndPlay("standstill") during the tick. Once you reach 150, your sprite stops moving, so it is perpetually at x=150. This means each tick will tell it to gotoAndPlay the same frame, resulting it in being "stuck".
Figured out a way around it, still not sure why but easaljs didn't like the code
if(leftwalker.x == 150)
{
leftwalker.gotoAndPlay("standstill");
}
When I change it so the char isn't stuck on point 150 (move him to 151) the animation begins. I also slowed the animation on the standing still down to make it seem more real but this isn't related to the fix I didn't post this code.
if(leftwalker.x == 150)
{
leftwalker.gotoAndPlay("standstill");
if(leftwalker.x < 180)
{
leftwalker.x += 1;
}
}
Is the pinch zoom touch gesture supported in CreateJS? I can not find anything in the docs.
Thanks
There is no native support for gestures but once you enable it touch events are translated into mouse events and identified by pointerID property. Based on this I have been able implemented the pinch zoom gesture in my project (though I have not tested it beyond latest Android.)
This is a snippet from my project:
stage.on("mousedown", function (evt : createjs.MouseEvent) {
if (evt.pointerID == 0 || evt.pointerID == -1) { //touch 1 or mouse
touch1 = new createjs.Point(stage.globalToLocal(evt.stageX, 0).x, stage.globalToLocal(0, evt.stageY).y);
} else if (evt.pointerID == 1) { //touch 2
touch2 = new createjs.Point(stage.globalToLocal(evt.stageX, 0).x, stage.globalToLocal(0, evt.stageY).y);
}
});
stage.on("pressup", function (evt : createjs.MouseEvent) {
if (evt.pointerID == 0 || evt.pointerID == -1) { //touch 1 or mouse
touch1 = null;
} else if (evt.pointerID == 1) { //touch 2
touch2 = null;
}
});
stage.on("pressmove", function(evt : createjs.MouseEvent) {
if (evt.pointerID == -1 || evt.pointerID == 0) {
var touch = touch1;
} else if (evt.pointerID == 1) {
var touch = touch2;
}
var dX = stage.globalToLocal(evt.stageX, 0).x - touch.x;
var dY = stage.globalToLocal(0, evt.stageY).y - touch.y;
if (touch1 && touch2) var oldDist = distanceP(touch1, touch2);
touch.x += dX;
touch.y += dY;
//if both fingers are used zoom and move the canvas
if (touch1 && touch2) {
var newDist = distanceP(touch1, touch2);
var newZoom = zoom * newDist / oldDist;
zoomMap(newZoom, new createjs.Point((touch1.x+touch2.x)/2, (touch1.y + touch2.y)/2))
//if both fingers are used apply only half of the motion to each of them
dX /= 2;
dY /= 2;
}
map.x += dX;
map.y += dY;
stage.update();
});
function distanceP(p1 : createjs.Point, p2 : createjs.Point) : number {
return Math.sqrt((p2.x-p1.x)*(p2.x-p1.x) + (p2.y-p1.y)*(p2.y-p1.y));
}
function zoomMap(newZoom : number, zoomCenter : createjs.Point) {
....
}
NOTE: I am moving and zooming DO called Map. The stage itself is zoomed due to various devicePixelRatio's (retina display etc), that's why the use of globalToLocal functions.
No. EaselJS handles normal mouse events (to determine what is clicked), as well as some drag events, since determining a drag target is a common usage. Additionally, touch events are translated into mouse events (including multi-touch).
Things like swipe, pinch, and other gestures are not handled by the framework at this time.
I'm having some trouble with synthesizing an advanced object projection formula. I have already figured out few basic physic simulation formulas such as:
Velocity of object:
x += cos(angle);
y += sin(angle);
*where angle can be obtained by either mouse position or with tan(...target and intial values)
but that only travels straight based on the angle.
Gravity:
Yvelocity = Yvelocity - gravity;
if(!isHitPlatform) {
Obj.y += YVelocity
}
Bounce:// No point if we've not been sized...
if (height > 0) {
// Are we bouncing...
if (bounce) {
// Add the vDelta to the yPos
// vDelta may be postive or negative, allowing
// for both up and down movement...
yPos += vDelta;
// Add the gravity to the vDelta, this will slow down
// the upward movement and speed up the downward movement...
// You may wish to place a max speed to this
vDelta += gDelta;
// If the sprite is not on the ground...
if (yPos + SPRITE_HEIGHT >= height) {
// Seat the sprite on the ground
yPos = height - SPRITE_HEIGHT;
// If the re-bound delta is 0 or more then we've stopped
// bouncing...
if (rbDelta >= 0) {
// Stop bouncing...
bounce = false;
} else {
// Add the re-bound degregation delta to the re-bound delta
rbDelta += rbDegDelta;
// Set the vDelta...
vDelta = rbDelta;
}
}
}
}
I need help way to combine these three formulas to create an efficient and lightweight algorithm that allows an object to be projected in an arch determined by the angle, yet continues to bounce a few times before coming to a stop, all with an acceptable amount of discontinuity between each point. *Note: Having the grenade be determined by a f(x) = -x^2 formula creates a larger jump discontinuity as the slope increases, forcing you to reverse the formula to find x = +-y value (to determine whether + or -, check the bounds).
something like:
class granade
{
private static final double dt = 0.1; // or similar
private double speedx;
private double speedy;
private double positionx;
private double positiony;
public granade(double v, double angle)
{
speedx = v * Math.cos(angle);
speedy = v * Math.sin(angle);
positionx = 0;
positiony = 0;
}
public void nextframe()
{
// update speed: v += a*dt
speedy -= gravity* dt;
// update position: pos += v*dt
positionx += speedx * dt;
double newpositiony = positiony + speedy*dt;
// bounce if hit ground
if (newpositiony > 0)
positiony = newpositiony;
else {
// bounce vertically
speedy *= -1;
positiony = -newpositiony;
}
}
public void draw() { /* TODO */ }
}
OT: avoid Math.atan(y/x), use Math.atan2(y, x)
I am trying to develop a logic to recognize a circle which is made by users right hand, I got the code to draw the skeleton and track from the sample code,
private void SensorSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
Skeleton[] skeletons = new Skeleton[0];
using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame != null)
{
skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
skeletonFrame.CopySkeletonDataTo(skeletons);
}
}
using (DrawingContext dc = this.drawingGroup.Open())
{
// Draw a transparent background to set the render size
dc.DrawRectangle(Brushes.Black, null, new Rect(0.0, 0.0, RenderWidth, RenderHeight));
if (skeletons.Length != 0)
{
foreach (Skeleton skel in skeletons)
{
RenderClippedEdges(skel, dc);
if (skel.TrackingState == SkeletonTrackingState.Tracked)
{
this.DrawBonesAndJoints(skel, dc);
}
else if (skel.TrackingState == SkeletonTrackingState.PositionOnly)
{
dc.DrawEllipse(
this.centerPointBrush,
null,
this.SkeletonPointToScreen(skel.Position),
BodyCenterThickness,
BodyCenterThickness);
}
}
}
// prevent drawing outside of our render area
this.drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0.0, 0.0, RenderWidth, RenderHeight));
}
}
What I want to do now is to track the coordinates of users right hand for gesture recognition,
Here is how I am planning to get the job done:
Start the gesture
Draw the circled gesture, Make sure to store the coordinates for start and then keep noting the coordinates for every 45 degree shift of the Joint from the start, for 8 octants we will get 8 samples.
For making a decision that a circle was drawn we can just check the relation ship between the eight samples.
Also, in the depthimage I want to show the locus of the drawn gesture, so as the handpoint moves it leaves a trace behind so at the end we will get a figure which was drawn by an user. I have no idea how to achieve this.
Coordinates for each joint are available for each tracked skeleton during each SkeletonFrameReady event. Inside your foreach loop...
foreach (Skeleton skeleton in skeletons) {
// get the joint
Joint rightHand = skeleton.Joints[JointType.HandRight];
// get the individual points of the right hand
double rightX = rightHand.Position.X;
double rightY = rightHand.Position.Y;
double rightZ = rightHand.Position.Z;
}
You can look at the JointType enum to pull out any of the joints and work with the individual coordinates.
To draw your gesture trail you can use the DrawContext you have in your example or use another way to draw a Path onto the visual layer. With your x/y/z values, you would need to scale them to the window coordinates. The "Coding4Fun" library offers a pre-built function to do it; alternatively you can write your own, for example:
private static double ScaleY(Joint joint)
{
double y = ((SystemParameters.PrimaryScreenHeight / 0.4) * -joint.Position.Y) + (SystemParameters.PrimaryScreenHeight / 2);
return y;
}
private static void ScaleXY(Joint shoulderCenter, bool rightHand, Joint joint, out int scaledX, out int scaledY)
{
double screenWidth = SystemParameters.PrimaryScreenWidth;
double x = 0;
double y = ScaleY(joint);
// if rightHand then place shouldCenter on left of screen
// else place shouldCenter on right of screen
if (rightHand)
{
x = (joint.Position.X - shoulderCenter.Position.X) * screenWidth * 2;
}
else
{
x = screenWidth - ((shoulderCenter.Position.X - joint.Position.X) * (screenWidth * 2));
}
if (x < 0)
{
x = 0;
}
else if (x > screenWidth - 5)
{
x = screenWidth - 5;
}
if (y < 0)
{
y = 0;
}
scaledX = (int)x;
scaledY = (int)y;
}
I have an app that draws a grid of dots (let's say 5x5). The user is asked to draw lines on that grid. If the user's finger touches one of the dots in the grid, this dot is being colored to show that this dot is part of a path drawn. In addition a line will be drawn between each two touched dots.
The issue - I get very bad performance, which causes few things:
The application gets really slow.
Motion events in event.getAction() get bad granularity. I meanenter code here that instead of registering a movement each 10 pixels for example, it registers movements each 100 pixels. This, in turn, will causes the app to NOT redraw some dots the user had touched.
Sometimes the motion coordinates are simple wrong: lets say the user is moving her finger from pixel 100 to pixel 500, the reading might show 100...200...150...140...300...400. For some reason the touch location gets messed up in some cases.
Look at the example on how the app "misses out" on dots the user have touched and doesn't draw the green dots:
I've tried few thing:
Adding Thread.sleep(100); to else if(event.getAction() == MotionEvent.ACTION_MOVE) inside onTouchEvent(MotionEvent event), I read that this might give the CPU time to catch up on all those touch events - didn't change a thing
Adding this.destroyDrawingCache() to the very end of doDraw() (I use it instead of onDraw, as was suggested by one tutorial I used). I thought this will clear all event/drawing caching which seems to be slowing down the system - didn't change a thing.
I am fairly new to Android animation so I am not sure how to proceed:
I understand I should do as little as possible in doDraw() (my onDraw()) and onTouchEvent().
I read some stuff about invalidate() but not sure how and when to use it. If I understand correctly, my View gets drawn anew each time doDraw() is called. My grid, for instance, is static - how can I avoid redrawing it?
++++++++++++++++++++++++ UPDATE 7th Oct +++++++++++++++++++++
I tried using canvas.drawCircle(xPos, yPos, 8, mNodePaint); instead of canvas.drawBitmap(mBitmap, xPos, yPos, null);. I thought that if I DIDN'T use actual bitmaps this might improve performance. As a matter of fact - it didn't! I am a bit confused how such a simple application can pose such a heavy load on the device. I must be doing something really the wrong way.
++++++++++++++++++++++++ UPDATE 12th Oct +++++++++++++++++++++
I took into account what #LadyWoodi suggested - I've eliminated all variable declarations out of the loops - anyway it is a bad practice and I also got rid of all the "System.Out" lines I use so I can log app behavior to better understand why I get such a lame performance. I am sad to say that if there was a change in performance (I didn't actually measure frame rate change) it is negligible.
Any other ideas?
++++++++++++++++++++++++ UPDATE 13th Oct +++++++++++++++++++++
As I have a static grid of dots (see hollow black/white dots in screenShot) that never changes during the game I did the following:
-Draw the grid once.
-Capture the drawing as bitmap using Bitmap.createBitmap().
-Use canvas.drawBitmap() to draw the bitmap of the static dots grid.
-When my thread runs I check to see it the grid of dots is drawn. If it is running I will NOT recreate the static dots grid. I will only render it from my previously rendered bitmap.
Surprisingly this changed nothing with my performance! Redrawing the dots grid each time didn't have a true visual effect on app performance.
I decided to use canvas = mHolder.lockCanvas(new Rect(50, 50, 150, 150)); inside my drawing thread. It was just for testing purposes to see if I limit the area rendered each time, I can get the performance better. This DID NOT help either.
Then I turned to the DDMS tool in Eclipse to try and profile the app. What it came up with, was that canvas.drawPath(path, mPathPaint); (Canvas.native_drawPath) consumed about 88.5% of CPU time!!!
But why??! My path drawing is rather simple, mGraphics contains a collection of Paths and all I do is figure out if each path is inside the boundaries of the game screen and then I draw a path:
//draw path user is creating with her finger on screen
for (Path path : mGraphics)
{
//get path values
mPm = new PathMeasure(path, true);
mPm.getPosTan(0f, mStartCoordinates, null);
//System.out.println("aStartCoordinates X:" + aStartCoordinates[0] + " aStartCoordinates Y:" + aStartCoordinates[1]);
mPm.getPosTan(mPm.getLength(), mEndCoordinates, null);
//System.out.println("aEndCoordinates X:" + aEndCoordinates[0] + " aEndCoordinates Y:" + aEndCoordinates[1]);
//coordinates are within game board boundaries
if((mStartCoordinates[0] >= 1 && mStartCoordinates[1] >= 1) && (mEndCoordinates[0] >= 1 && mEndCoordinates[1] >= 1))
{
canvas.drawPath(path, mPathPaint);
}
}
Can anyone see any ill programmed lines of code in my examples?
++++++++++++++++++++++++ UPDATE 14th Oct +++++++++++++++++++++
I've made changes to my doDraw()method. Basically what I do is draw the screen ONLY if something was changed. In all other cases I simply store a cached bitmap of the screen and render it. Please take a look:
public void doDraw(Canvas canvas)
{
synchronized (mViewThread.getSurefaceHolder())
{
if(mGraphics.size() > mPathsCount)
{
mPathsCount = mGraphics.size();
//draw path user is creating with her finger on screen
for (Path path : mGraphics)
{
//get path values
mPm = new PathMeasure(path, true);
mPm.getPosTan(0f, mStartCoordinates, null);
//System.out.println("aStartCoordinates X:" + aStartCoordinates[0] + " aStartCoordinates Y:" + aStartCoordinates[1]);
mPm.getPosTan(mPm.getLength(), mEndCoordinates, null);
//System.out.println("aEndCoordinates X:" + aEndCoordinates[0] + " aEndCoordinates Y:" + aEndCoordinates[1]);
//coordinates are within game board boundaries
if((mStartCoordinates[0] >= 1 && mStartCoordinates[1] >= 1) && (mEndCoordinates[0] >= 1 && mEndCoordinates[1] >= 1))
{
canvas.drawPath(path, mPathPaint);
}
}
//nodes that the path goes through, are repainted green
//these nodes are building the drawn pattern
for (ArrayList<PathPoint> nodePattern : mNodesHitPatterns)
{
for (PathPoint nodeHit : nodePattern)
{
canvas.drawBitmap(mDotOK, nodeHit.x - ((mDotOK.getWidth()/2) - (mNodeBitmap.getWidth()/2)), nodeHit.y - ((mDotOK.getHeight()/2) - (mNodeBitmap.getHeight()/2)), null);
}
}
mGameField = Bitmap.createBitmap(mGridNodesCount * mNodeGap, mGridNodesCount * mNodeGap, Bitmap.Config.ARGB_8888);
}
else
{
canvas.drawBitmap(mGameField, 0f, 0f, null);
}
Now for the results - as long as the device doesn't have to render no paths and simply draws from a bitmap, stuff goes very fast. But the moment I have to rerender the screen using canvas.drawPath() performance becomes as sluggish as a turtle on morphine... The more paths I have (up to 6 and more, which is NOTHING!) the slower the rendering. How odd is this?? - My paths are even not really curvy - the are all straight lines with an occasional turn. What I mean is that the line is not very "complex".
I've add more code below - if you have any improvements ideas.
Many thanks in advance,
D.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Class "Panel" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public class Panel extends SurfaceView implements SurfaceHolder.Callback {
Bitmap mNodeBitmap;
int mNodeBitmapWidthCenter;
int mNodeBitmapHeightCenter;
Bitmap mDotOK;
ViewThread mViewThread;
ArrayList<PathPoint> mPathPoints;
private ArrayList<Path> mGraphics = new ArrayList<Path>(3);
private ArrayList<ArrayList<PathPoint>> mNodesHitPatterns = new ArrayList<ArrayList<PathPoint>>();
private Paint mPathPaint;
Path mPath = new Path();
//private ArrayList<Point> mNodeCoordinates = new ArrayList<Point>();
private int mGridNodesCount = 5;
private int mNodeGap = 100;
PathPoint mNodeCoordinates[][] = new PathPoint[mGridNodesCount][mGridNodesCount];
PathMeasure mPm;
float mStartCoordinates[] = {0f, 0f};
float mEndCoordinates[] = {0f, 0f};
PathPoint mPathPoint;
Boolean mNodesGridDrawn = false;
Bitmap mGameField = null;
public Boolean getNodesGridDrawn() {
return mNodesGridDrawn;
}
public Panel(Context context) {
super(context);
mNodeBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot);
mNodeBitmapWidthCenter = mNodeBitmap.getWidth()/2;
mNodeBitmapHeightCenter = mNodeBitmap.getHeight()/2;
mDotOK = BitmapFactory.decodeResource(getResources(), R.drawable.dot_ok);
getHolder().addCallback(this);
mViewThread = new ViewThread(this);
mPathPaint = new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setDither(true); //for better color
mPathPaint.setColor(0xFFFFFF00);
mPathPaint.setStyle(Paint.Style.STROKE);
mPathPaint.setStrokeJoin(Paint.Join.ROUND);
mPathPaint.setStrokeCap(Paint.Cap.ROUND);
mPathPaint.setStrokeWidth(5);
}
public ArrayList<ArrayList<PathPoint>> getNodesHitPatterns()
{
return this.mNodesHitPatterns;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
//setPadding(100, 100, 0, 0);
if (!mViewThread.isAlive()) {
mViewThread = new ViewThread(this);
mViewThread.setRunning(true);
mViewThread.start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (mViewThread.isAlive()) {
mViewThread.setRunning(false);
}
}
//draw the basic nodes grid that the user will use to draw the lines on
//store as bitmap
public void drawNodesGrid(Canvas canvas)
{
canvas.drawColor(Color.WHITE);
for (int i = 0; i < mGridNodesCount; i++)
{
for (int j = 0; j < mGridNodesCount; j++)
{
int xPos = j * mNodeGap;
int yPos = i * mNodeGap;
try
{
//TODO - changed
mNodeCoordinates[i][j] = new PathPoint(xPos, yPos, null);
}
catch (Exception e)
{
e.printStackTrace();
}
canvas.drawBitmap(mNodeBitmap, xPos, yPos, null);
}
}
mNodesGridDrawn = true;
mGameField = Bitmap.createBitmap(mGridNodesCount * mNodeGap, mGridNodesCount * mNodeGap, Bitmap.Config.ARGB_8888);
}
public void doDraw(Canvas canvas)
{
canvas.drawBitmap(mGameField, 0f, 0f, null);
synchronized (mViewThread.getSurefaceHolder())
{
//draw path user is creating with her finger on screen
for (Path path : mGraphics)
{
//get path values
mPm = new PathMeasure(path, true);
mPm.getPosTan(0f, mStartCoordinates, null);
//System.out.println("aStartCoordinates X:" + aStartCoordinates[0] + " aStartCoordinates Y:" + aStartCoordinates[1]);
mPm.getPosTan(mPm.getLength(), mEndCoordinates, null);
//System.out.println("aEndCoordinates X:" + aEndCoordinates[0] + " aEndCoordinates Y:" + aEndCoordinates[1]);
//coordinates are within game board boundaries
if((mStartCoordinates[0] >= 1 && mStartCoordinates[1] >= 1) && (mEndCoordinates[0] >= 1 && mEndCoordinates[1] >= 1))
{
canvas.drawPath(path, mPathPaint);
}
}
//nodes that the path goes through, are repainted green
//these nodes are building the drawn pattern
for (ArrayList<PathPoint> nodePattern : mNodesHitPatterns)
{
for (PathPoint nodeHit : nodePattern)
{
canvas.drawBitmap(mDotOK, nodeHit.x - ((mDotOK.getWidth()/2) - (mNodeBitmap.getWidth()/2)), nodeHit.y - ((mDotOK.getHeight()/2) - (mNodeBitmap.getHeight()/2)), null);
}
}
this.destroyDrawingCache();
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
synchronized (mViewThread.getSurefaceHolder()) {
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
//System.out.println("Action downE x: " + event.getX() + " y: " + event.getY());
for (int i = 0; i < mGridNodesCount; i++)
{
for (int j = 0; j < mGridNodesCount; j++)
{
//TODO - changed
//PathPoint pathPoint = mNodeCoordinates[i][j];
mPathPoint = mNodeCoordinates[i][j];
if((Math.abs((int)event.getX() - mPathPoint.x) <= 35) && (Math.abs((int)event.getY() - mPathPoint.y) <= 35))
{
//mPath.moveTo(pathPoint.x + mBitmap.getWidth() / 2, pathPoint.y + mBitmap.getHeight() / 2);
//System.out.println("Action down x: " + pathPoint.x + " y: " + pathPoint.y);
ArrayList<PathPoint> newNodesPattern = new ArrayList<PathPoint>();
mNodesHitPatterns.add(newNodesPattern);
//mNodesHitPatterns.add(nh);
//pathPoint.setAction("down");
break;
}
}
}
}
else if(event.getAction() == MotionEvent.ACTION_MOVE)
{
final int historySize = event.getHistorySize();
//System.out.println("historySize: " + historySize);
//System.out.println("Action moveE x: " + event.getX() + " y: " + event.getY());
coordinateFound:
for (int i = 0; i < mGridNodesCount; i++)
{
for (int j = 0; j < mGridNodesCount; j++)
{
//TODO - changed
//PathPoint pathPoint = mNodeCoordinates[i][j];
mPathPoint = mNodeCoordinates[i][j];
if((Math.abs((int)event.getX() - mPathPoint.x) <= 35) && (Math.abs((int)event.getY() - mPathPoint.y) <= 35))
{
int lastPatternIndex = mNodesHitPatterns.size()-1;
ArrayList<PathPoint> lastPattern = mNodesHitPatterns.get(lastPatternIndex);
int lastPatternLastNode = lastPattern.size()-1;
if(lastPatternLastNode != -1)
{
if(!mPathPoint.equals(lastPattern.get(lastPatternLastNode).x, lastPattern.get(lastPatternLastNode).y))
{
lastPattern.add(mPathPoint);
//System.out.println("Action moveC [add point] x: " + pathPoint.x + " y: " + pathPoint.y);
}
}
else
{
lastPattern.add(mPathPoint);
//System.out.println("Action moveC [add point] x: " + pathPoint.x + " y: " + pathPoint.y);
}
break coordinateFound;
}
else //no current match => try historical
{
if(historySize > 0)
{
for (int k = 0; k < historySize; k++)
{
//System.out.println("Action moveH x: " + event.getHistoricalX(k) + " y: " + event.getHistoricalY(k));
if((Math.abs((int)event.getHistoricalX(k) - mPathPoint.x) <= 35) && (Math.abs((int)event.getHistoricalY(k) - mPathPoint.y) <= 35))
{
int lastPatternIndex = mNodesHitPatterns.size()-1;
ArrayList<PathPoint> lastPattern = mNodesHitPatterns.get(lastPatternIndex);
int lastPatternLastNode = lastPattern.size()-1;
if(lastPatternLastNode != -1)
{
if(!mPathPoint.equals(lastPattern.get(lastPatternLastNode).x, lastPattern.get(lastPatternLastNode).y))
{
lastPattern.add(mPathPoint);
//System.out.println("Action moveH [add point] x: " + pathPoint.x + " y: " + pathPoint.y);
}
}
else
{
lastPattern.add(mPathPoint);
//System.out.println("Action moveH [add point] x: " + pathPoint.x + " y: " + pathPoint.y);
}
break coordinateFound;
}
}
}
}
}
}
}
else if(event.getAction() == MotionEvent.ACTION_UP)
{
// for (int i = 0; i < mGridSize; i++) {
//
// for (int j = 0; j < mGridSize; j++) {
//
// PathPoint pathPoint = mNodeCoordinates[i][j];
//
// if((Math.abs((int)event.getX() - pathPoint.x) <= 35) && (Math.abs((int)event.getY() - pathPoint.y) <= 35))
// {
// //the location of the node
// //mPath.lineTo(pathPoint.x + mBitmap.getWidth() / 2, pathPoint.y + mBitmap.getHeight() / 2);
//
// //System.out.println("Action up x: " + pathPoint.x + " y: " + pathPoint.y);
//
// //mGraphics.add(mPath);
// // mNodesHit.add(pathPoint);
// // pathPoint.setAction("up");
// break;
// }
// }
// }
}
//System.out.println(mNodesHitPatterns.toString());
//create mPath
for (ArrayList<PathPoint> nodePattern : mNodesHitPatterns)
{
for (int i = 0; i < nodePattern.size(); i++)
{
if(i == 0) //first node in pattern
{
mPath.moveTo(nodePattern.get(i).x + mNodeBitmapWidthCenter, nodePattern.get(i).y + mNodeBitmapHeightCenter);
}
else
{
mPath.lineTo(nodePattern.get(i).x + mNodeBitmapWidthCenter, nodePattern.get(i).y + mNodeBitmapWidthCenter);
}
//mGraphics.add(mPath);
}
}
mGraphics.add(mPath);
return true;
}
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Class "ViewThread" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public class ViewThread extends Thread {
private Panel mPanel;
private SurfaceHolder mHolder;
private boolean mRun = false;
public ViewThread(Panel panel) {
mPanel = panel;
mHolder = mPanel.getHolder();
}
public void setRunning(boolean run) {
mRun = run;
}
public SurfaceHolder getSurefaceHolder()
{
return mHolder;
}
#Override
public void run()
{
Canvas canvas = null;
while (mRun)
{
canvas = mHolder.lockCanvas();
//canvas = mHolder.lockCanvas(new Rect(50, 50, 150, 150));
if (canvas != null)
{
if(!mPanel.getNodesGridDrawn())
{
mPanel.drawNodesGrid(canvas);
}
mPanel.doDraw(canvas);
mHolder.unlockCanvasAndPost(canvas);
}
}
}
}
It's just the idea, but I would try to take all the declarations out of the loops. I know that it can be useful to have them localized, however it's usually really time consuming so it could help a little. My second idea was already tested by you in your update so now I am also curious how it will go ;)
You are using a SurfaceView? First of all, I recommend you to use a graphic library for your game... AndEngine for example is pretty easy to use and you will achieve to develop a much more beautiful game than using the Java canvas. The performance is better too.
I canĀ“t find anything wrong with your code, but there is a lot of processing in the draw method, and more important, in the onTouch event. You should avoid to use divisions or heavy math operations in the loops and try to pre-calculate everything before.
But I insist; for something like what you are doing, take a look at this and you will have it up and running in no time!