-
Notifications
You must be signed in to change notification settings - Fork 17
Сделал дз. #7
base: master
Are you sure you want to change the base?
Сделал дз. #7
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package ru.ok.technopolis.basketball.CustomView; | ||
|
||
import android.content.Context; | ||
import android.content.res.TypedArray; | ||
import android.graphics.Canvas; | ||
import android.graphics.Color; | ||
import android.graphics.Paint; | ||
import android.graphics.Path; | ||
import android.support.annotation.Nullable; | ||
import android.util.AttributeSet; | ||
import android.util.DisplayMetrics; | ||
import android.util.TypedValue; | ||
import android.view.View; | ||
|
||
import ru.ok.technopolis.basketball.R; | ||
|
||
public class FieldView extends View { | ||
|
||
private Float currentX; | ||
private Float currentY; | ||
private Paint dotPaint = new Paint(); | ||
private Path dotPath = new Path(); | ||
private int pointRadius; | ||
private static final int DEFAULT_POINT_COLOR = Color.BLACK; | ||
public FieldView(Context context) { | ||
super(context); | ||
} | ||
|
||
public FieldView(Context context, @Nullable AttributeSet attrs) { | ||
super(context, attrs); | ||
|
||
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); | ||
int pointStrokeWidthFromAttr = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, R.dimen.default_point_stroke_width, displayMetrics) + 0.5f); | ||
int pointRadiusFromAttr = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, R.dimen.default_point_radius, displayMetrics) + 0.5f); | ||
int pointColorFromAttr = DEFAULT_POINT_COLOR; | ||
if (attrs != null) { | ||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FieldView); | ||
pointStrokeWidthFromAttr = typedArray.getDimensionPixelOffset(R.styleable.FieldView_pointStrokeWidth, pointStrokeWidthFromAttr); | ||
pointRadiusFromAttr = typedArray.getDimensionPixelSize(R.styleable.FieldView_pointRadius, pointRadiusFromAttr); | ||
pointColorFromAttr = typedArray.getColor(R.styleable.FieldView_pointColor, pointColorFromAttr); | ||
typedArray.recycle(); | ||
} | ||
|
||
dotPaint.setStyle(Paint.Style.STROKE); | ||
dotPaint.setColor(pointColorFromAttr); | ||
dotPaint.setStrokeWidth(pointStrokeWidthFromAttr); | ||
pointRadius = pointRadiusFromAttr; | ||
} | ||
|
||
@Override | ||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | ||
super.onMeasure(widthMeasureSpec, heightMeasureSpec); | ||
} | ||
|
||
@Override | ||
protected void onDraw(Canvas canvas) { | ||
if (currentX == null || currentY == null) { | ||
canvas.drawPath(dotPath, dotPaint); | ||
return; | ||
} | ||
dotPath.addCircle(currentX, currentY, pointRadius, Path.Direction.CW); | ||
canvas.drawPath(dotPath, dotPaint); | ||
} | ||
|
||
public void drawDot(float x, float y) { | ||
currentX = x; | ||
currentY = y; | ||
invalidate(); | ||
} | ||
|
||
public void clearField() { | ||
dotPath.reset(); | ||
currentX = null; | ||
currentY = null; | ||
invalidate(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package ru.ok.technopolis.basketball.CustomView; | ||
|
||
import android.content.Context; | ||
import android.content.res.TypedArray; | ||
import android.graphics.Canvas; | ||
import android.graphics.Color; | ||
import android.graphics.Paint; | ||
import android.graphics.Path; | ||
import android.support.annotation.Nullable; | ||
import android.util.AttributeSet; | ||
import android.util.DisplayMetrics; | ||
import android.util.TypedValue; | ||
import android.view.View; | ||
|
||
import ru.ok.technopolis.basketball.R; | ||
|
||
public class ScoreView extends View { | ||
|
||
private static final int DEFAULT_MARK_COLOR = Color.BLACK; | ||
private Path markPath = new Path(); | ||
private Paint markPaint = new Paint(); | ||
|
||
public ScoreView(Context context) { | ||
super(context); | ||
} | ||
|
||
public ScoreView(Context context, @Nullable AttributeSet attrs) { | ||
super(context, attrs); | ||
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); | ||
int markStrokeWidthFromAttr = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, R.dimen.default_point_stroke_width, displayMetrics) + 0.5f); | ||
int markColorFromAttr = DEFAULT_MARK_COLOR; | ||
if (attrs != null) { | ||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScoreView); | ||
markStrokeWidthFromAttr = typedArray.getDimensionPixelSize(R.styleable.ScoreView_markStrokeWidth, markStrokeWidthFromAttr); | ||
markColorFromAttr = typedArray.getColor(R.styleable.ScoreView_markColor, markColorFromAttr); | ||
typedArray.recycle(); | ||
} | ||
markPaint.setStyle(Paint.Style.STROKE); | ||
markPaint.setColor(markColorFromAttr); | ||
markPaint.setStrokeWidth(markStrokeWidthFromAttr); | ||
} | ||
|
||
@Override | ||
protected void onDraw(Canvas canvas) { | ||
canvas.drawPath(markPath, markPaint); | ||
} | ||
|
||
public void setMark(int mark) { | ||
resetMark(); | ||
int leftPadding = getPaddingLeft(); | ||
int rightPadding = getPaddingRight(); | ||
int topPadding = getPaddingTop(); | ||
int bottomPadding = getPaddingBottom(); | ||
int width = getWidth() / 5 - leftPadding - rightPadding; | ||
int xStart = width / 2 + leftPadding; | ||
int yStart = getHeight() - bottomPadding; | ||
int xEnd; | ||
int yEnd; | ||
for (int i = 0; i < mark; i++) { | ||
markPath.moveTo(xStart, yStart); | ||
xEnd = xStart + width / 2; | ||
yEnd = yStart - getHeight() + topPadding + bottomPadding; | ||
markPath.lineTo(xEnd, yEnd); | ||
markPath.moveTo(xStart, yStart); | ||
xEnd = xStart - width / 2; | ||
yEnd = yStart - getHeight() / 2 + bottomPadding; | ||
markPath.lineTo(xEnd, yEnd); | ||
xStart += (width + leftPadding + rightPadding); | ||
} | ||
invalidate(); | ||
} | ||
|
||
public void resetMark() { | ||
markPath.reset(); | ||
invalidate(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,133 @@ | ||
package ru.ok.technopolis.basketball; | ||
|
||
import android.support.v7.app.AppCompatActivity; | ||
import android.animation.ValueAnimator; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Аниматоры стоит сохранять в поля и во время уничтожения активити останавливать анимации |
||
import android.annotation.SuppressLint; | ||
import android.content.Context; | ||
import android.os.Bundle; | ||
import android.support.v7.app.AppCompatActivity; | ||
import android.view.MotionEvent; | ||
import android.view.VelocityTracker; | ||
import android.view.View; | ||
import android.view.animation.LinearInterpolator; | ||
import android.widget.Toast; | ||
|
||
import ru.ok.technopolis.basketball.CustomView.FieldView; | ||
import ru.ok.technopolis.basketball.CustomView.ScoreView; | ||
|
||
public class MainActivity extends AppCompatActivity { | ||
public class MainActivity extends AppCompatActivity implements View.OnTouchListener { | ||
|
||
private View ball; | ||
private FieldView fieldView; | ||
private ScoreView scoreView; | ||
private View hoop; | ||
private View player; | ||
private VelocityTracker velocityTracker; | ||
private Point startPoint; | ||
private MotionOfProjectile motionOfProjectile; | ||
private float currentX; | ||
private float currentY; | ||
private Context context; | ||
private float G = 9800; | ||
private float maxDistance; | ||
ValueAnimator animator; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Можно сделать private |
||
|
||
@SuppressLint("ClickableViewAccessibility") | ||
@Override | ||
protected void onCreate(Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
setContentView(R.layout.activity_main); | ||
fieldView = findViewById(R.id.field_view_basketball_field); | ||
fieldView.setOnTouchListener(this); | ||
ball = findViewById(R.id.image_ball); | ||
float density = getResources().getDisplayMetrics().density; | ||
hoop = findViewById(R.id.image_hoop); | ||
player = findViewById(R.id.image_player); | ||
scoreView = findViewById(R.id.score_view_score); | ||
context = this; | ||
G = G / density; | ||
} | ||
|
||
@SuppressLint("ClickableViewAccessibility") | ||
@Override | ||
public boolean onTouch(View v, MotionEvent event) { | ||
switch (event.getAction()) { | ||
case MotionEvent.ACTION_DOWN: | ||
velocityTracker = VelocityTracker.obtain(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Перед тем как взять новый velocityTracker лучше проверить что нет старого, а если есть, то сделать ему recycle |
||
break; | ||
case MotionEvent.ACTION_UP: | ||
fieldView.clearField(); | ||
scoreView.resetMark(); | ||
velocityTracker.computeCurrentVelocity(1000); | ||
calculateInitialCondition(event.getX(), event.getY(), velocityTracker.getXVelocity(), velocityTracker.getYVelocity()); | ||
initialiseAnimation(); | ||
velocityTracker.recycle(); | ||
break; | ||
case MotionEvent.ACTION_MOVE: | ||
velocityTracker.addMovement(event); | ||
break; | ||
case MotionEvent.ACTION_CANCEL: | ||
break; | ||
} | ||
ball.setTranslationX(event.getX() - ball.getLeft() - ball.getWidth() / 2); | ||
ball.setTranslationY(event.getY() - ball.getTop() - ball.getHeight() / 2); | ||
return true; | ||
} | ||
|
||
void calculateInitialCondition(float x0, float y0, float vx0, float vy0) { | ||
startPoint = new Point(x0, y0, vx0, vy0); | ||
startPoint.changeVerticalAxisTo(fieldView.getHeight()); | ||
motionOfProjectile = new MotionOfProjectile(startPoint, G); | ||
} | ||
|
||
void initialiseAnimation() { | ||
if (isScored(startPoint.getX(), fieldView.getHeight() - startPoint.getY())) { | ||
Toast.makeText(context, R.string.cheater, Toast.LENGTH_SHORT).show(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Интересное решение =) |
||
return; | ||
} | ||
float timeStart = 0; | ||
animator = ValueAnimator.ofFloat(timeStart, motionOfProjectile.getTimeFlight()); | ||
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | ||
@Override | ||
public void onAnimationUpdate(ValueAnimator animation) { | ||
currentX = motionOfProjectile.getXFromTime((float) animation.getAnimatedValue()); | ||
currentY = fieldView.getHeight() - motionOfProjectile.getYFromTime((float) animation.getAnimatedValue()); | ||
ball.setX(currentX - ball.getWidth() / 2); | ||
ball.setY(currentY - ball.getHeight() / 2); | ||
if (isScored(currentX, currentY)) { | ||
Toast.makeText(context, R.string.goll, Toast.LENGTH_SHORT).show(); | ||
maxDistance = Point.getDistance(player.getWidth(), fieldView.getHeight() - player.getHeight(), currentX, currentY); | ||
startPoint.changeVerticalAxisTo(fieldView.getHeight()); | ||
scoreView.setMark(calculateScore(maxDistance, startPoint.getDistance(currentX, currentY))); | ||
|
||
} | ||
fieldView.drawDot(currentX, currentY); | ||
if (animation.getAnimatedValue().equals(motionOfProjectile.getTimeFlight())) { | ||
Toast.makeText(context, R.string.not_goll, Toast.LENGTH_SHORT).show(); | ||
} | ||
} | ||
}); | ||
animator.setInterpolator(new LinearInterpolator()); | ||
animator.setDuration(2000); | ||
animator.start(); | ||
} | ||
|
||
private boolean isScored(float x, float y) { | ||
if (x > (hoop.getLeft() + hoop.getWidth() / 2 - hoop.getWidth() / 6) && x < (hoop.getLeft() + hoop.getWidth() / 2 + hoop.getWidth() / 6)) { | ||
if (y > (hoop.getTop() + hoop.getHeight() / 3) && y < (hoop.getTop() + hoop.getHeight() / 2 + hoop.getHeight() / 3)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
@Override | ||
protected void onPause() { | ||
super.onPause(); | ||
animator.cancel(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. animator стоит проверить на нул. Иначе, если не делать бросков и свернуть приложение будет креш |
||
} | ||
|
||
private int calculateScore(float maxDist, float dist) { | ||
int score = (int) (dist / (maxDist / 4)) + 1; | ||
return score > 5 ? 5 : score; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package ru.ok.technopolis.basketball; | ||
|
||
public class MotionOfProjectile { | ||
|
||
private Point point; | ||
private float G; | ||
|
||
MotionOfProjectile(Point point, float G) { | ||
this.point = point; | ||
this.G = G; | ||
} | ||
|
||
public float getTimeFlight() { | ||
float t1 = (float) (-point.getVy() + Math.sqrt(point.getVy() * point.getVy() + 2 * G * point.getY())) / (-G); | ||
float t2 = (float) (-point.getVy() - Math.sqrt(point.getVy() * point.getVy() + 2 * G * point.getY())) / (-G); | ||
return t1 > t2 ? t1 : t2; | ||
} | ||
|
||
public float getXFromTime(float t) { | ||
return point.getX() + point.getVx() * t; | ||
} | ||
|
||
public float getYFromTime(float t) { | ||
return (point.getY() + point.getVy() * t - G * t * t / 2); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package ru.ok.technopolis.basketball; | ||
|
||
public class Point { | ||
|
||
private float x; | ||
private float y; | ||
private float vx; | ||
private float vy; | ||
|
||
public Point(float coordinate) { | ||
this(coordinate, coordinate); | ||
} | ||
|
||
public Point(float x, float y) { | ||
this(x, y, 0, 0); | ||
} | ||
|
||
public Point(float x, float y, float vx, float vy) { | ||
this.x = x; | ||
this.y = y; | ||
this.vx = vx; | ||
this.vy = vy; | ||
} | ||
|
||
public float getX() { | ||
return x; | ||
} | ||
|
||
public float getY() { | ||
return y; | ||
} | ||
|
||
public float getVx() { | ||
return vx; | ||
} | ||
|
||
public float getVy() { | ||
return vy; | ||
} | ||
|
||
public float getDistance(float x, float y) { | ||
return (float) Math.sqrt((this.x - x) * (this.x - x) + (this.y - y) * (this.y - y)); | ||
} | ||
|
||
public static float getDistance(float x1, float y1, float x2, float y2) { | ||
return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); | ||
} | ||
|
||
public void changeVerticalAxisTo(float y0) { | ||
y = y0 - y; | ||
vy = -vy; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Что бы каждый раз не делать +0.5f и не забывать про это, лучше сделать метод для перевода из dp в px