Skip to content
This repository has been archived by the owner on Mar 1, 2021. It is now read-only.

Сделал дз. #7

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
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.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 = Utils.pxFromDP(displayMetrics, R.dimen.default_point_stroke_width);
int pointRadiusFromAttr = Utils.pxFromDP(displayMetrics, R.dimen.default_point_radius);
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 = Utils.pxFromDP(displayMetrics, R.dimen.default_point_stroke_width);
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
@@ -0,0 +1,10 @@
package ru.ok.technopolis.basketball.CustomView;

import android.util.DisplayMetrics;
import android.util.TypedValue;

public final class Utils {
public static int pxFromDP(DisplayMetrics displayMetrics, int res){
return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, res, displayMetrics) + 0.5f);
}
}
126 changes: 124 additions & 2 deletions app/src/main/java/ru/ok/technopolis/basketball/MainActivity.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,135 @@
package ru.ok.technopolis.basketball;

import android.support.v7.app.AppCompatActivity;
import android.animation.ValueAnimator;
Copy link

Choose a reason for hiding this comment

The 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;
private ValueAnimator animator;

@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();
Copy link

Choose a reason for hiding this comment

The 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();
Copy link

Choose a reason for hiding this comment

The 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();
if (animator != null){
animator.cancel();
}
}

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);
}
}
53 changes: 53 additions & 0 deletions app/src/main/java/ru/ok/technopolis/basketball/Point.java
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;
}
}
Loading