public static final int SQUARE = 0,
LINE = 1,
S_FIGURE = 2,
Z_FIGURE = 3,
RIGHT_ANGLE_FIGURE = 4,
LEFT_ANGLE_FIGURE = 5,
TRIANGLE = 6;
Here above is my Tetris midlet/J2ME code for the block. But i don't know how to explain these parameters. can anyone give me advice? Let me know if you need the full code to work.
this is my full code:
public class Block {
public static final int SQUARE = 0,
LINE = 1,
S_FIGURE = 2,
Z_FIGURE = 3,
RIGHT_ANGLE_FIGURE = 4,
LEFT_ANGLE_FIGURE = 5,
TRIANGLE = 6;
public int kind;
public int color;
/**
* The horizontal figure position on the board. This value has no
* meaning when the figure is not attached to a square board.
*/
public int xPos = 0;
/**
* The vertical figure position on the board. This value has no
* meaning when the figure is not attached to a square board.
*/
public int yPos = 0;
/**
* The figure orientation (or rotation). This value is normally
* between 0 and 3, but must also be less than the maxOrientation
* value.
*
* #see #maxOrientation
*/
private int orientation = 0;
public int maxOrientation;
public int[] shapeX, shapeY;
private GameCanvas board = null;
public Block(int k) {
shapeX = new int[4];
shapeY = new int[4];
initialize(k);
this.kind = k;
}
private void initialize(int kind) {
switch (kind) {
case SQUARE :
maxOrientation = 1;
color = 0x0000ff; // blau
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = -1;
shapeY[2] = 1;
shapeX[3] = 0;
shapeY[3] = 1;
break;
case LINE :
maxOrientation = 2;
color = 0xff0000; // rot
shapeX[0] = -2;
shapeY[0] = 0;
shapeX[1] = -1;
shapeY[1] = 0;
shapeX[2] = 0;
shapeY[2] = 0;
shapeX[3] = 1;
shapeY[3] = 0;
break;
case S_FIGURE :
maxOrientation = 2;
color = 0xff00ff; // lila
shapeX[0] = 0;
shapeY[0] = 0;
shapeX[1] = 1;
shapeY[1] = 0;
shapeX[2] = -1;
shapeY[2] = 1;
shapeX[3] = 0;
shapeY[3] = 1;
break;
case Z_FIGURE :
maxOrientation = 2;
color = 0x008000; // grün
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = 0;
shapeY[2] = 1;
shapeX[3] = 1;
shapeY[3] = 1;
break;
case RIGHT_ANGLE_FIGURE :
maxOrientation = 4;
color = 0x800080; // violett
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = 1;
shapeY[2] = 0;
shapeX[3] = 1;
shapeY[3] = 1;
break;
case LEFT_ANGLE_FIGURE :
maxOrientation = 4;
color = 0x000000; // schwarz
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = 1;
shapeY[2] = 0;
shapeX[3] = -1;
shapeY[3] = 1;
break;
case TRIANGLE :
maxOrientation = 4; // gelb
color = 0xCECE00;
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = 1;
shapeY[2] = 0;
shapeX[3] = 0;
shapeY[3] = 1;
break;
}
}
/**
* Checks if this figure is attached to a square board.
*
* #return true if the figure is already attached, or
* false otherwise
*/
public boolean isAttached() {
return board != null;
}
public boolean attach(GameCanvas board, boolean center) {
int newX;
int newY;
int i;
// Check for previous attachment
if (isAttached()) {
detach();
}
// Reset position (for correct controls)
xPos = 0;
yPos = 0;
// Calculate position
newX = board.getBoardWidth() / 2;
if (center) {
newY = board.getBoardHeight() / 2;
} else {
newY = 0;
for (i = 0; i < shapeX.length; i++) {
if (getRelativeY(i, orientation) < 0 && getRelativeY(i, orientation)<newY) {
newY = Math.abs(getRelativeY(i, orientation))+1;
}
}
}
// Check position
this.board = board;
if (!canMoveTo(newX, newY, orientation)) {
this.board = null;
return false;
}
// Draw figure
xPos = newX;
yPos = newY;
paint(color);
board.repaint();
return true;
}
/**
* Checks if the figure is fully visible on the square board. If
* the figure isn't attached to a board, false will be returned.
*
* #return true if the figure is fully visible, or
* false otherwise
*/
public boolean isAllVisible() {
if (!isAttached()) {
return false;
}
for (int i = 0; i < shapeX.length; i++) {
if (yPos + getRelativeY(i, orientation) < 0) {
return false;
}
}
return true;
}
/**
* Detaches this figure from its square board. The figure will not
* be removed from the board by this operation, resulting in the
* figure being left intact.
*/
public void detach() {
board = null;
}
/**
* Checks if the figure has landed. If this method returns true,
* the moveDown() or the moveAllWayDown() methods should have no
* effect. If no square board is attached, this method will return
* true.
*
* #return true if the figure has landed, or false otherwise
*/
public boolean hasLanded() {
return !isAttached() || !canMoveTo(xPos, yPos + 1, orientation);
}
/**
* Moves the figure one step to the left. If such a move is not
* possible with respect to the square board, nothing is done. The
* square board will be changed as the figure moves, clearing the
* previous cells. If no square board is attached, nothing is
* done.
*/
public void moveLeft() {
if (isAttached() && canMoveTo(xPos - 1, yPos, orientation)) {
paint(-1);
xPos--;
paint(color);
board.repaint();
}
}
/**
* Moves the figure one step to the right. If such a move is not
* possible with respect to the square board, nothing is done. The
* square board will be changed as the figure moves, clearing the
* previous cells. If no square board is attached, nothing is
* done.
*/
public void moveRight() {
if (isAttached() && canMoveTo(xPos + 1, yPos, orientation)) {
paint(-1);
xPos++;
paint(color);
board.repaint();
}
}
/**
* Moves the figure one step down. If such a move is not possible
* with respect to the square board, nothing is done. The square
* board will be changed as the figure moves, clearing the
* previous cells. If no square board is attached, nothing is
* done.
*/
public void moveDown() {
if (isAttached() && canMoveTo(xPos, yPos + 1, orientation)) {
paint(-1);
yPos++;
paint(color);
board.repaint();
}
}
/**
* Moves the figure all the way down. The limits of the move are
* either the square board bottom, or squares not being empty. If
* no move is possible with respect to the square board, nothing
* is done. The square board will be changed as the figure moves,
* clearing the previous cells. If no square board is attached,
* nothing is done.
*/
public void moveAllWayDown() {
int y = yPos;
// Check for board
if (!isAttached()) {
return;
}
// Find lowest position
while (canMoveTo(xPos, y + 1, orientation)) {
y++;
}
// Update
if (y != yPos) {
paint(-1);
yPos = y;
paint(color);
board.repaint();
}
}
/**
* Returns the current figure rotation (orientation).
*
* #return the current figure rotation
*/
public int getRotation() {
return orientation;
}
/**
* Sets the figure rotation (orientation). If the desired rotation
* is not possible with respect to the square board, nothing is
* done. The square board will be changed as the figure moves,
* clearing the previous cells. If no square board is attached,
* the rotation is performed directly.
*
* #param rotation the new figure orientation
*/
public void setRotation(int rotation) {
int newOrientation;
// Set new orientation
newOrientation = rotation % maxOrientation;
// Check new position
if (!isAttached()) {
orientation = newOrientation;
} else if (canMoveTo(xPos, yPos, newOrientation)) {
paint(-1);
orientation = newOrientation;
paint(color);
board.repaint();
}
}
/**
* Rotates the figure clockwise. If such a rotation is not
* possible with respect to the square board, nothing is done.
* The square board will be changed as the figure moves,
* clearing the previous cells. If no square board is attached,
* the rotation is performed directly.
*/
public void rotateClockwise() {
if (maxOrientation == 1) {
return;
} else {
setRotation((orientation + 1) % maxOrientation);
}
}
/**
* Rotates the figure counter-clockwise. If such a rotation
* is not possible with respect to the square board, nothing
* is done. The square board will be changed as the figure
* moves, clearing the previous cells. If no square board is
* attached, the rotation is performed directly.
*/
public void rotateCounterClockwise() {
if (maxOrientation == 1) {
return;
} else {
setRotation((orientation + 3) % 4);
}
}
/**
* Checks if a specified pair of (square) coordinates are inside
* the figure, or not.
*
* #param x the horizontal position
* #param y the vertical position
*
* #return true if the coordinates are inside the figure, or
* false otherwise
*/
private boolean isInside(int x, int y) {
for (int i = 0; i < shapeX.length; i++) {
if (x == xPos + getRelativeX(i, orientation)
&& y == yPos + getRelativeY(i, orientation)) {
return true;
}
}
return false;
}
/**
* Checks if the figure can move to a new position. The current
* figure position is taken into account when checking for
* collisions. If a collision is detected, this method will return
* false.
*
* #param newX the new horizontal position
* #param newY the new vertical position
* #param newOrientation the new orientation (rotation)
*
* #return true if the figure can be moved, or
* false otherwise
*/
private boolean canMoveTo(int newX, int newY, int newOrientation) {
int x;
int y;
for (int i = 0; i < 4; i++) {
x = newX + getRelativeX(i, newOrientation);
y = newY + getRelativeY(i, newOrientation);
if (!isInside(x, y) && !board.isSquareEmpty(x, y)) {
return false;
}
}
return true;
}
/**
* Returns the relative horizontal position of a specified square.
* The square will be rotated according to the specified
* orientation.
*
* #param square the square to rotate (0-3)
* #param orientation the orientation to use (0-3)
*
* #return the rotated relative horizontal position
*/
public int getRelativeX(int square, int orientation) {
switch (orientation % 4) {
case 0 :
return shapeX[square];
case 1 :
return -shapeY[square];
case 2 :
return -shapeX[square];
case 3 :
return shapeY[square];
default:
return 0; // Should never occur
}
}
/**
* Rotates the relative vertical position of a specified square.
* The square will be rotated according to the specified
* orientation.
*
* #param square the square to rotate (0-3)
* #param orientation the orientation to use (0-3)
*
* #return the rotated relative vertical position
*/
public int getRelativeY(int square, int orientation) {
switch (orientation % 4) {
case 0 :
return shapeY[square];
case 1 :
return shapeX[square];
case 2 :
return -shapeY[square];
case 3 :
return -shapeX[square];
default:
return 0; // Should never occur
}
}
/**
* Paints the figure on the board with the specified color.
*
* #param color the color to paint with, or -1 for clearing
*/
private void paint(int color) {
int x, y;
for (int i = 0; i < shapeX.length; i++) {
x = xPos + getRelativeX(i, orientation);
y = yPos + getRelativeY(i, orientation);
board.setSquareColor(x, y, color);
}
}
}
First of all, I think what you're looking for is an enum:
public enum Tetrimonos{
SQUARE , LINE, S_FIGURE, Z_FIGURE ,
RIGHT_ANGLE_FIGURE, LEFT_ANGLE_FIGURE , TRIANGLE
}
Using constants is a bad idea, relic from old languages.
Secondly, what do you mean 'explain these parameters'? Explain the tetris structure of each thing you named? In this case you should go to the relevant literature: a tetris piece is called tetrimono, and each one is called by a letter. Take a look here:
http://en.wikipedia.org/wiki/Tetris#Gameplay
You might like to link to this in your documentation as well.
Related
My flood fill algorithm works, however, I cannot print the 6 main colors of my game. The Java function that allows me to print the 2-d array is in the class GameModel.java called toString():
import java.util.Random;
public class GameModel {
/**
* predefined values to capture the color of a DotInfo
*/
public static final int COLOR_0 = 0;
public static final int COLOR_1 = 1;
public static final int COLOR_2 = 2;
public static final int COLOR_3 = 3;
public static final int COLOR_4 = 4;
public static final int COLOR_5 = 5;
public static final int NUMBER_OF_COLORS = 6;
private static DotInfo[][] dots;
private int size;
private int currentColor;
private Random generator;
private int steps;
/**
* Constructor to initialize the model to a given size of board.
*
* #param size
* the size of the board
*/
public GameModel(int size) {
this.size = size;
dots = new DotInfo[size][size];
generator = new Random();
}
/**
* Resets the model to (re)start a game. The previous game (if there is one)
* is cleared up .
*/
public void reset(){
generator = new Random();
int color = 0;
for (int j=0;j<size;j++) {
for (int i=0;i<size;i++) {
dots[j][i] = new DotInfo(i, j, generator.nextInt(NUMBER_OF_COLORS)+1);
}
}
}
/**
* Getter method for the size of the game
*
* #return the value of the attribute sizeOfGame
*/
public int getSize(){
return size;
}
/**
* returns the current color of a given dot in the game
*
* #param i
* the x coordinate of the dot
* #param j
* the y coordinate of the dot
* #return the status of the dot at location (i,j)
*/
public int getColor(int i, int j){
return dots[j][i].getColor();
}
/**
* returns true is the dot is captured, false otherwise
*
* #param i
* the x coordinate of the dot
* #param j
* the y coordinate of the dot
* #return the status of the dot at location (i,j)
*/
public boolean isCaptured(int i, int j){
return dots[j][i].isCaptured();
}
/**
* Sets the status of the dot at coordinate (i,j) to captured
*
* #param i
* the x coordinate of the dot
* #param j
* the y coordinate of the dot
*/
public void capture(int i, int j){
dots[j][i] = new DotInfo(i, j, currentColor);
dots[j][i].setCaptured(true);
}
/**
* Getter method for the current number of steps
*
* #return the current number of steps
*/
public int getNumberOfSteps(){
return steps;
}
/**
* Setter method for currentSelectedColor
*
* #param val
* the new value for currentSelectedColor
*/
public void setCurrentSelectedColor(int val) {
currentColor = val;
}
/**
* Getter method for currentSelectedColor
*
* #return currentSelectedColor
*/
public int getCurrentSelectedColor() {
return currentColor;
}
/**
* Getter method for the model's dotInfo reference
* at location (i,j)
*
* #param i
* the x coordinate of the dot
* #param j
* the y coordinate of the dot
*
* #return model[i][j]
*/
public DotInfo get(int i, int j) {
return dots[j][i];
}
/**
* The metod <b>step</b> updates the number of steps. It must be called
* once the model has been updated after the payer selected a new color.
*/
public void step(){
steps++;
}
/**
* The metod <b>isFinished</b> returns true iff the game is finished, that
* is, all the dats are captured.
*
* #return true if the game is finished, false otherwise
*/
public boolean isFinished(){
boolean flag=true;
for (int y=0;y<size;y++) {
for (int x=0;x<size;x++) {
if (dots[y][x].isCaptured()==false) {
flag=false;
}
}
}
return flag;
}
/**
* Builds a String representation of the model
*
* #return String representation of the model
*/
public String toString(){
String rep = "";
for (int y=0;y<size;y++) {
for (int x=0;x<size;x++) {
rep += dots[y][x].getColor()+" ";
}
rep+="\n";
}
return rep;
}
}
The function where I am printing the array is in my GameController.java class with the call:
System.out.println(model)
.
import java.awt.*;
public class GameController /*implements ActionListener*/ {
private GameModel model;
private MyStack dots;
private int size;
/**
* Constructor used for initializing the controller. It creates the game's view
* and the game's model instances
*
* #param size
* the size of the board on which the game will be played
*/
public GameController(int size) {
this.size = size;
model = new GameModel(size);
dots = new MyStack(size*size);
}
/**
* resets the game
*/
public void reset(){
model.reset();
System.out.println(model);
}
/**
* Callback used when the user clicks a button (reset or quit)
*
* #param e
* the ActionEvent
*/
/*public void actionPerformed(ActionEvent e) {
}*/
/**
* <b>selectColor</b> is the method called when the user selects a new color.
* If that color is not the currently selected one, then it applies the logic
* of the game to capture possible locations. It then checks if the game
* is finished, and if so, congratulates the player, showing the number of
* moves, and gives two options: start a new game, or exit
* #param color
* the newly selected color
*/
public void selectColor(int color){
model.setCurrentSelectedColor(color);
capturePointAtZero();
sendCapturedToStack();
equalityCheck(color);
System.out.println(model);
}
private void capturePointAtZero() {
int x = 0, y = 0;
if (!model.isCaptured(x, y)) {
model.capture(x, y);
}
}
private void sendCapturedToStack() {
for (int j=0;j<size;j++) {
for (int i=0;i<size;i++) {
if (model.isCaptured(i, j)) {
model.capture(i,j);
dots.push(model.get(i,j));
}
}
}
}
private void equalityCheck(int newColor) {
while (!dots.isEmpty()) {
DotInfo dot = dots.pop();
int x = dot.getX();
int y = dot.getY();
if (model.getColor(x,y+1)==newColor && !model.isCaptured(x,y+1)) {
model.capture(x, y+1);
dots.push(model.get(x,y+1));
} if (model.getColor(x+1,y)==newColor && !model.isCaptured(x+1,y)) {
model.capture(x+1, y);
dots.push(model.get(x+1,y));
} if (model.getColor(x,y-1)==newColor && !model.isCaptured(x,y-1)) {
model.capture(x, y-1);
dots.push(model.get(x,y-1));
} if (model.getColor(x-1,y)==newColor && !model.isCaptured(x-1,y)) {
model.capture(x-1, y);
dots.push(model.get(x-1,y));
}
}
}
}
I am getting a IndexOutOfBoundsError when it approaches the end of the matrix.
If anyone could help that would be much appreciated.
There are too many issues with the code to fix all of them. Still here a few the I noticed after a quick look:
Yes, the reason why the matrix is filled with 0 is that currentColor is 0 becuase you don't call setCurrentSelectedColor
A deeper issue is with logic. Let's look at equalityCheck
if (model.getColor(x, y + 1) == newColor && !model.isCaptured(x, y + 1))
{
model.capture(x, y + 1);
dots.push(model.get(x, y + 1));
}
This code means that dot at (x, y+1) will be updated only if it already has the newColor. Obviously you want it to be updated if it matches the "old color" i.e. color of the (0,0) but you don't even try to save that color in your capturePointAtZero!
Code such as
public void capture(int i, int j){
for (int y=0;y<size;y++) {
for (int x=0;x<size;x++) {
if (x==i && y==j) {
dots[y][x] = new DotInfo(x, y, currentColor);
dots[y][x].setCaptured(true);
}
}
}
}
is rather inefficient. Why do you need loops if you still update only single DotInfo? It can be simplified
public void capture(int i, int j){
dots[j][i] = new DotInfo(i, j, currentColor);
dots[j][i].setCaptured(true);
}
Hope this helps.
Update
I understand your comments but now I am getting an arrayIndexOutOfBounds whenever i call a number that is at the end of my Matrix.
Exception most probably happens because you don't validate your indices in the equalityCheck. You can add a method isValidPosition such as:
public class GameModel
{
....
public boolean isValidPosition(int x, int y)
{
return (x >= 0) && (x < size) && (y >= 0) && (y < size);
}
}
and then
private void equalityCheck(int newColor)
{
...
if (model.isValidPosition(x, y+1) && model.getColor(x, y + 1) == newColor && !model.isCaptured(x, y + 1))
{
model.capture(x, y + 1);
dots.push(model.get(x, y + 1));
}
Note that it is important that isValidPosition is the first call in the compound if. This works because Java uses short-circuit evaluation for boolean statements.
You can hide isValidPosition inside your other methods in the GameModel and sometimes similar approach is the right thing to do. But I don't think this is the time because 1) it requires you to return some fake value from getColor (you now use 0 and I don't really like it) and 2) it hides from the reader the business-logic that the field is not unlimited.
this is page-curl view , i want when nextView() is called my TextView get the next string
but I can't use TextView from xml layout it gives me null ,
how I can but buttons and TextView in customView ?
can any one help me to solve this with code ?
I have searched with many tutorials but I get this understanding
activity class :
public class StandaloneExample extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.standalone_example);
}
#Override
public void onDestroy(){
super.onDestroy();
System.gc();
finish();
}
/**
* Set the current orientation to landscape. This will prevent the OS from changing
* the app's orientation.
*/
public void lockOrientationLandscape() {
lockOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
/**
* Set the current orientation to portrait. This will prevent the OS from changing
* the app's orientation.
*/
public void lockOrientationPortrait() {
lockOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
public void lockOrientation( int orientation ) {
setRequestedOrientation(orientation);
}
}
pageCurlView :
public class PageCurlView extends View {
private class Vector2D {
public float x, y;
public Vector2D(float x, float y) {
this.x = x;
this.y = y;
}
#Override
public String toString() {
// TODO Auto-generated method stub
return "(" + this.x + "," + this.y + ")";
}
public float length() {
return (float) Math.sqrt(x * x + y * y);
}
public float lengthSquared() {
return (x * x) + (y * y);
}
public boolean equals(Object o) {
if (o instanceof Vector2D) {
Vector2D p = (Vector2D) o;
return p.x == x && p.y == y;
}
return false;
}
public Vector2D reverse() {
return new Vector2D(-x, -y);
}
public Vector2D sum(Vector2D b) {
return new Vector2D(x + b.x, y + b.y);
}
public Vector2D sub(Vector2D b) {
return new Vector2D(x - b.x, y - b.y);
}
public float dot(Vector2D vec) {
return (x * vec.x) + (y * vec.y);
}
public float cross(Vector2D a, Vector2D b) {
return a.cross(b);
}
public float cross(Vector2D vec) {
return x * vec.y - y * vec.x;
}
public float distanceSquared(Vector2D other) {
float dx = other.x - x;
float dy = other.y - y;
return (dx * dx) + (dy * dy);
}
public float distance(Vector2D other) {
return (float) Math.sqrt(distanceSquared(other));
}
public float dotProduct(Vector2D other) {
return other.x * x + other.y * y;
}
public Vector2D normalize() {
float magnitude = (float) Math.sqrt(dotProduct(this));
return new Vector2D(x / magnitude, y / magnitude);
}
public Vector2D mult(float scalar) {
return new Vector2D(x * scalar, y * scalar);
}
}
/**
* Inner class used to make a fixed timed animation of the curl effect.
*/
class FlipAnimationHandler extends Handler {
#Override
public void handleMessage(Message msg) {
PageCurlView.this.FlipAnimationStep();
}
public void sleep(long millis) {
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), millis);
}
}
/**
* Base
*
* #param context
*/
public PageCurlView(Context context) {
super(context);
init(context);
ResetClipEdge();
}
/**
* Construct the object from an XML file. Valid Attributes:
*
* #see android.view.View#View(android.content.Context,
* android.util.AttributeSet)
*/
public PageCurlView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
// Get the data from the XML AttributeSet
{
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.PageCurlView);
// Get data
bEnableDebugMode = a.getBoolean(
R.styleable.PageCurlView_enableDebugMode, bEnableDebugMode);
mCurlSpeed = a.getInt(R.styleable.PageCurlView_curlSpeed,
mCurlSpeed);
mUpdateRate = a.getInt(R.styleable.PageCurlView_updateRate,
mUpdateRate);
mInitialEdgeOffset = a.getInt(
R.styleable.PageCurlView_initialEdgeOffset,
mInitialEdgeOffset);
mCurlMode = a.getInt(R.styleable.PageCurlView_curlMode, mCurlMode);
Log.i(TAG, "mCurlSpeed: " + mCurlSpeed);
Log.i(TAG, "mUpdateRate: " + mUpdateRate);
Log.i(TAG, "mInitialEdgeOffset: " + mInitialEdgeOffset);
Log.i(TAG, "mCurlMode: " + mCurlMode);
// recycle object (so it can be used by others)
a.recycle();
}
ResetClipEdge();
}
/**
* Initialize the view
*/
private final void init(Context context) {
LayoutInflater.from(context).inflate(R.layout.standalone_example, null,
true);
// left text view
textViewContent = (TextView) this.findViewById(R.id.textView);
// Foreground text paint
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(16);
mTextPaint.setColor(0xFF000000);
// The shadow
mTextPaintShadow = new TextPaint();
mTextPaintShadow.setAntiAlias(true);
mTextPaintShadow.setTextSize(16);
mTextPaintShadow.setColor(0x00000000);
// Cache the context
mContext = new WeakReference<Context>(context);
hesham = context;
// Base padding
setPadding(3, 3, 3, 3);
// The focus flags are needed
setFocusable(true);
setFocusableInTouchMode(true);
mMovement = new Vector2D(0, 0);
mFinger = new Vector2D(0, 0);
mOldMovement = new Vector2D(0, 0);
// Create our curl animation handler
mAnimationHandler = new FlipAnimationHandler();
// Create our edge paint
mCurlEdgePaint = new Paint();
mCurlEdgePaint.setColor(Color.WHITE);
mCurlEdgePaint.setAntiAlias(true);
mCurlEdgePaint.setStyle(Paint.Style.FILL);
mCurlEdgePaint.setShadowLayer(10, -5, 5, 0x99000000);
// Set the default props, those come from an XML :D
mCurlSpeed = 120;
mUpdateRate = 66;
mInitialEdgeOffset = 30;
mCurlMode = 2;
// LEGACY PAGE HANDLING!
// Create pages
mPages = new ArrayList<Bitmap>();
mPages.add(BitmapFactory.decodeResource(getResources(),
R.drawable.page1));
mPages.add(BitmapFactory.decodeResource(getResources(),
R.drawable.page2));
// Create some sample images
mForeground = mPages.get(0);
mBackground = mPages.get(1);
}
/**
* Reset points to it's initial clip edge state
*/
public void ResetClipEdge() {
// Set our base movement
mMovement.x = mInitialEdgeOffset;
mMovement.y = mInitialEdgeOffset;
mOldMovement.x = 0;
mOldMovement.y = 0;
// Now set the points
// TODO: OK, those points MUST come from our measures and
// the actual bounds of the view!
mA = new Vector2D(mInitialEdgeOffset, 0);
mB = new Vector2D(this.getWidth(), this.getHeight());
mC = new Vector2D(this.getWidth(), 0);
mD = new Vector2D(0, 0);
mE = new Vector2D(0, 0);
mF = new Vector2D(0, 0);
mOldF = new Vector2D(0, 0);
// The movement origin point
mOrigin = new Vector2D(this.getWidth(), 0);
}
/**
* Return the context which created use. Can return null if the context has
* been erased.
*/
private Context GetContext() {
return mContext.get();
}
/**
* See if the current curl mode is dynamic
*
* #return TRUE if the mode is CURLMODE_DYNAMIC, FALSE otherwise
*/
public boolean IsCurlModeDynamic() {
return mCurlMode == CURLMODE_DYNAMIC;
}
/**
* Set the curl speed.
*
* #param curlSpeed
* - New speed in px/frame
* #throws IllegalArgumentException
* if curlspeed < 1
*/
public void SetCurlSpeed(int curlSpeed) {
if (curlSpeed < 1)
throw new IllegalArgumentException(
"curlSpeed must be greated than 0");
mCurlSpeed = curlSpeed;
}
/**
* Get the current curl speed
*
* #return int - Curl speed in px/frame
*/
public int GetCurlSpeed() {
return mCurlSpeed;
}
/**
* Set the update rate for the curl animation
*
* #param updateRate
* - Fixed animation update rate in fps
* #throws IllegalArgumentException
* if updateRate < 1
*/
public void SetUpdateRate(int updateRate) {
if (updateRate < 1)
throw new IllegalArgumentException(
"updateRate must be greated than 0");
mUpdateRate = updateRate;
}
/**
* Get the current animation update rate
*
* #return int - Fixed animation update rate in fps
*/
public int GetUpdateRate() {
return mUpdateRate;
}
/**
* Set the initial pixel offset for the curl edge
*
* #param initialEdgeOffset
* - px offset for curl edge
* #throws IllegalArgumentException
* if initialEdgeOffset < 0
*/
public void SetInitialEdgeOffset(int initialEdgeOffset) {
if (initialEdgeOffset < 0)
throw new IllegalArgumentException(
"initialEdgeOffset can not negative");
mInitialEdgeOffset = initialEdgeOffset;
}
/**
* Get the initial pixel offset for the curl edge
*
* #return int - px
*/
public int GetInitialEdgeOffset() {
return mInitialEdgeOffset;
}
/**
* Set the curl mode.
* <p>
* Can be one of the following values:
* </p>
* <table>
* <colgroup align="left" /> <colgroup align="left" />
* <tr>
* <th>Value</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>
* <code>{#link #CURLMODE_SIMPLE com.dcg.pagecurl:CURLMODE_SIMPLE}</code></td>
* <td>Curl target will move only in one axis.</td>
* </tr>
* <tr>
* <td>
* <code>{#link #CURLMODE_DYNAMIC com.dcg.pagecurl:CURLMODE_DYNAMIC}</code></td>
* <td>Curl target will move on both X and Y axis.</td>
* </tr>
* </table>
*
* #see #CURLMODE_SIMPLE
* #see #CURLMODE_DYNAMIC
* #param curlMode
* #throws IllegalArgumentException
* if curlMode is invalid
*/
public void SetCurlMode(int curlMode) {
if (curlMode != CURLMODE_SIMPLE && curlMode != CURLMODE_DYNAMIC)
throw new IllegalArgumentException("Invalid curlMode");
mCurlMode = curlMode;
}
/**
* Return an integer that represents the current curl mode.
* <p>
* Can be one of the following values:
* </p>
* <table>
* <colgroup align="left" /> <colgroup align="left" />
* <tr>
* <th>Value</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>
* <code>{#link #CURLMODE_SIMPLE com.dcg.pagecurl:CURLMODE_SIMPLE}</code></td>
* <td>Curl target will move only in one axis.</td>
* </tr>
* <tr>
* <td>
* <code>{#link #CURLMODE_DYNAMIC com.dcg.pagecurl:CURLMODE_DYNAMIC}</code></td>
* <td>Curl target will move on both X and Y axis.</td>
* </tr>
* </table>
*
* #see #CURLMODE_SIMPLE
* #see #CURLMODE_DYNAMIC
* #return int - current curl mode
*/
public int GetCurlMode() {
return mCurlMode;
}
/**
* Enable debug mode. This will draw a lot of data in the view so you can
* track what is happening
*
* #param bFlag
* - boolean flag
*/
public void SetEnableDebugMode(boolean bFlag) {
bEnableDebugMode = bFlag;
}
/**
* Check if we are currently in debug mode.
*
* #return boolean - If TRUE debug mode is on, FALSE otherwise.
*/
public boolean IsDebugModeEnabled() {
return bEnableDebugMode;
}
/**
* #see android.view.View#measure(int, int)
*/
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int finalWidth, finalHeight;
finalWidth = measureWidth(widthMeasureSpec);
finalHeight = measureHeight(heightMeasureSpec);
setMeasuredDimension(finalWidth, finalHeight);
}
/**
* Determines the width of this view
*
* #param measureSpec
* A measureSpec packed into an int
* #return The width of the view, honoring constraints from measureSpec
*/
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text
result = specSize;
}
return result;
}
/**
* Determines the height of this view
*
* #param measureSpec
* A measureSpec packed into an int
* #return The height of the view, honoring constraints from measureSpec
*/
private int measureHeight(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = specSize;
}
return result;
}
/**
* Render the text
*
* #see android.view.View#onDraw(android.graphics.Canvas)
*/
// #Override
// protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
// canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent,
// mTextPaint);
// }
// ---------------------------------------------------------------
// Curling. This handles touch events, the actual curling
// implementations and so on.
// ---------------------------------------------------------------
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!bBlockTouchInput) {
// Get our finger position
mFinger.x = event.getX();
mFinger.y = event.getY();
int width = getWidth();
// Depending on the action do what we need to
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mOldMovement.x = mFinger.x;
mOldMovement.y = mFinger.y;
// If we moved over the half of the display flip to next
if (mOldMovement.x > (width >> 1)) {
mMovement.x = mInitialEdgeOffset;
mMovement.y = mInitialEdgeOffset;
// Set the right movement flag
bFlipRight = true;
} else {
// Set the left movement flag
bFlipRight = false;
// go to next previous page
previousView();
// Set new movement
mMovement.x = IsCurlModeDynamic() ? width << 1 : width;
mMovement.y = mInitialEdgeOffset;
}
break;
case MotionEvent.ACTION_UP:
bUserMoves = false;
bFlipping = true;
FlipAnimationStep();
break;
case MotionEvent.ACTION_MOVE:
bUserMoves = true;
// Get movement
mMovement.x -= mFinger.x - mOldMovement.x;
mMovement.y -= mFinger.y - mOldMovement.y;
mMovement = CapMovement(mMovement, true);
// Make sure the y value get's locked at a nice level
if (mMovement.y <= 1)
mMovement.y = 1;
// Get movement direction
if (mFinger.x < mOldMovement.x) {
bFlipRight = true;
} else {
bFlipRight = false;
}
// Save old movement values
mOldMovement.x = mFinger.x;
mOldMovement.y = mFinger.y;
// Force a new draw call
DoPageCurl();
this.invalidate();
break;
}
}
// TODO: Only consume event if we need to.
return true;
}
/**
* Make sure we never move too much, and make sure that if we move too much
* to add a displacement so that the movement will be still in our radius.
*
* #paramradius - radius form the flip origin
* #param bMaintainMoveDir
* - Cap movement but do not change the current movement
* direction
* #return Corrected point
*/
private Vector2D CapMovement(Vector2D point, boolean bMaintainMoveDir) {
// Make sure we never ever move too much
if (point.distance(mOrigin) > mFlipRadius) {
if (bMaintainMoveDir) {
// Maintain the direction
point = mOrigin.sum(point.sub(mOrigin).normalize()
.mult(mFlipRadius));
} else {
// Change direction
if (point.x > (mOrigin.x + mFlipRadius))
point.x = (mOrigin.x + mFlipRadius);
else if (point.x < (mOrigin.x - mFlipRadius))
point.x = (mOrigin.x - mFlipRadius);
point.y = (float) (Math.sin(Math.acos(Math.abs(point.x
- mOrigin.x)
/ mFlipRadius)) * mFlipRadius);
}
}
return point;
}
/**
* Execute a step of the flip animation
*/
public void FlipAnimationStep() {
if (!bFlipping)
return;
int width = getWidth();
// No input when flipping
bBlockTouchInput = true;
// Handle speed
float curlSpeed = mCurlSpeed;
if (!bFlipRight)
curlSpeed *= -1;
// Move us
mMovement.x += curlSpeed;
mMovement = CapMovement(mMovement, false);
// Create values
DoPageCurl();
// Check for endings :D
if (mA.x < 1 || mA.x > width - 1) {
bFlipping = false;
if (bFlipRight) {
// SwapViews();
nextView();
}
ResetClipEdge();
// Create values
DoPageCurl();
// Enable touch input after the next draw event
bEnableInputAfterDraw = true;
} else {
mAnimationHandler.sleep(mUpdateRate);
}
// Force a new draw call
this.invalidate();
}
/**
* Do the page curl depending on the methods we are using
*/
private void DoPageCurl() {
if (bFlipping) {
if (IsCurlModeDynamic())
doDynamicCurl();
else
doSimpleCurl();
} else {
if (IsCurlModeDynamic())
doDynamicCurl();
else
doSimpleCurl();
}
}
/**
* Do a simple page curl effect
*/
private void doSimpleCurl() {
int width = getWidth();
int height = getHeight();
// Calculate point A
mA.x = width - mMovement.x;
mA.y = height;
// Calculate point D
mD.x = 0;
mD.y = 0;
if (mA.x > width / 2) {
mD.x = width;
mD.y = height - (width - mA.x) * height / mA.x;
} else {
mD.x = 2 * mA.x;
mD.y = 0;
}
// Now calculate E and F taking into account that the line
// AD is perpendicular to FB and EC. B and C are fixed points.
double angle = Math
.atan((height - mD.y) / (mD.x + mMovement.x - width));
double _cos = Math.cos(2 * angle);
double _sin = Math.sin(2 * angle);
// And get F
mF.x = (float) (width - mMovement.x + _cos * mMovement.x);
mF.y = (float) (height - _sin * mMovement.x);
// If the x position of A is above half of the page we are still not
// folding the upper-right edge and so E and D are equal.
if (mA.x > width / 2) {
mE.x = mD.x;
mE.y = mD.y;
} else {
// So get E
mE.x = (float) (mD.x + _cos * (width - mD.x));
mE.y = (float) -(_sin * (width - mD.x));
}
}
/**
* Calculate the dynamic effect, that one that follows the users finger
*/
private void doDynamicCurl() {
int width = getWidth();
int height = getHeight();
// F will follow the finger, we add a small displacement
// So that we can see the edge
mF.x = width - mMovement.x + 0.1f;
mF.y = height - mMovement.y + 0.1f;
// Set min points
if (mA.x == 0) {
mF.x = Math.min(mF.x, mOldF.x);
mF.y = Math.max(mF.y, mOldF.y);
}
// Get diffs
float deltaX = width - mF.x;
float deltaY = height - mF.y;
float BH = (float) (Math.sqrt(deltaX * deltaX + deltaY * deltaY) / 2);
double tangAlpha = deltaY / deltaX;
double alpha = Math.atan(deltaY / deltaX);
double _cos = Math.cos(alpha);
double _sin = Math.sin(alpha);
mA.x = (float) (width - (BH / _cos));
mA.y = height;
mD.y = (float) (height - (BH / _sin));
mD.x = width;
mA.x = Math.max(0, mA.x);
if (mA.x == 0) {
mOldF.x = mF.x;
mOldF.y = mF.y;
}
// Get W
mE.x = mD.x;
mE.y = mD.y;
// Correct
if (mD.y < 0) {
mD.x = width + (float) (tangAlpha * mD.y);
mE.y = 0;
mE.x = width + (float) (Math.tan(2 * alpha) * mD.y);
}
}
/**
* Swap between the fore and back-ground.
*/
#Deprecated
private void SwapViews() {
Bitmap temp = mForeground;
mForeground = mBackground;
mBackground = temp;
}
/**
* Swap to next view
*/
private void nextView() {
MySQLiteHelper SqlLiteInstance = new MySQLiteHelper(hesham);
SqlLiteInstance.insertForTest("تايتل", "لبلب", "ثثث");
SqlLiteInstance.insertForTest("تايتل التاني", "5555", "5555");
SqlLiteInstance.insertForTest("التالت", "66666", "66666");
int foreIndex = mIndex + 1;
Cursor myDataBase = SqlLiteInstance.getCurrentPageData(1);
if (myDataBase.moveToFirst() && myDataBase.getCount() >= 1) {
do {
textViewContent.setText(myDataBase.getString(0));
} while (myDataBase.moveToNext());
}
if (foreIndex >= mPages.size()) {
foreIndex = 0;
}
int backIndex = foreIndex + 1;
if (backIndex >= mPages.size()) {
backIndex = 0;
}
mIndex = foreIndex;
setViews(foreIndex, backIndex);
}
/**
* Swap to previous view
*/
private void previousView() {
int backIndex = mIndex;
int foreIndex = backIndex - 1;
if (foreIndex < 0) {
foreIndex = mPages.size() - 1;
}
mIndex = foreIndex;
setViews(foreIndex, backIndex);
}
/**
* Set current fore and background
*
* #param foreground
* - Foreground view index
* #param background
* - Background view index
*/
private void setViews(int foreground, int background) {
mForeground = mPages.get(foreground);
mBackground = mPages.get(background);
}
// ---------------------------------------------------------------
// Drawing methods
// ---------------------------------------------------------------
#Override
protected void onDraw(Canvas canvas) {
// Always refresh offsets
mCurrentLeft = getLeft();
mCurrentTop = getTop();
// Translate the whole canvas
// canvas.translate(mCurrentLeft, mCurrentTop);
// We need to initialize all size data when we first draw the view
if (!bViewDrawn) {
bViewDrawn = true;
onFirstDrawEvent(canvas);
}
canvas.drawColor(Color.WHITE);
// Curl pages
// DoPageCurl();
// TODO: This just scales the views to the current
// width and height. We should add some logic for:
// 1) Maintain aspect ratio
// 2) Uniform scale
// 3) ...
Rect rect = new Rect();
rect.left = 0;
rect.top = 0;
rect.bottom = getHeight();
rect.right = getWidth();
// First Page render
Paint paint = new Paint();
// Draw our elements
drawForeground(canvas, rect, paint);
drawBackground(canvas, rect, paint);
drawCurlEdge(canvas);
// Draw any debug info once we are done
if (bEnableDebugMode)
drawDebug(canvas);
// Check if we can re-enable input
if (bEnableInputAfterDraw) {
bBlockTouchInput = false;
bEnableInputAfterDraw = false;
}
// Restore canvas
// canvas.restore();
}
/**
* Called on the first draw event of the view
*
* #param canvas
*/
protected void onFirstDrawEvent(Canvas canvas) {
mFlipRadius = getWidth();
ResetClipEdge();
DoPageCurl();
}
/**
* Draw the foreground
*
* #param canvas
* #param rect
* #param paint
*/
private void drawForeground(Canvas canvas, Rect rect, Paint paint) {
canvas.drawBitmap(mForeground, null, rect, paint);
// Draw the page number (first page is 1 in real life :D
// there is no page number 0 hehe)
drawPageNum(canvas, mIndex);
}
/**
* Create a Path used as a mask to draw the background page
*
* #return
*/
private Path createBackgroundPath() {
Path path = new Path();
path.moveTo(mA.x, mA.y);
path.lineTo(mB.x, mB.y);
path.lineTo(mC.x, mC.y);
path.lineTo(mD.x, mD.y);
path.lineTo(mA.x, mA.y);
return path;
}
/**
* Draw the background image.
*
* #param canvas
* #param rect
* #param paint
*/
private void drawBackground(Canvas canvas, Rect rect, Paint paint) {
Path mask = createBackgroundPath();
// Save current canvas so we do not mess it up
canvas.save();
canvas.clipPath(mask);
canvas.drawBitmap(mBackground, null, rect, paint);
// Draw the page number (first page is 1 in real life :D
// there is no page number 0 hehe)
drawPageNum(canvas, mIndex);
canvas.restore();
}
/**
* Creates a path used to draw the curl edge in.
*
* #return
*/
private Path createCurlEdgePath() {
Path path = new Path();
path.moveTo(mA.x, mA.y);
path.lineTo(mD.x, mD.y);
path.lineTo(mE.x, mE.y);
path.lineTo(mF.x, mF.y);
path.lineTo(mA.x, mA.y);
return path;
}
/**
* Draw the curl page edge
*
* #param canvas
*/
private void drawCurlEdge(Canvas canvas) {
Path path = createCurlEdgePath();
canvas.drawPath(path, mCurlEdgePaint);
}
/**
* Draw page num (let this be a bit more custom)
*
* #param canvas
* #param pageNum
*/
private void drawPageNum(Canvas canvas, int pageNum) {
mTextPaint.setColor(Color.WHITE);
String pageNumText = "- " + pageNum + " -";
drawCentered(canvas, pageNumText,
canvas.getHeight() - mTextPaint.getTextSize() - 5, mTextPaint,
mTextPaintShadow);
}
// ---------------------------------------------------------------
// Debug draw methods
// ---------------------------------------------------------------
/**
* Draw a text with a nice shadow
*/
public static void drawTextShadowed(Canvas canvas, String text, float x,
float y, Paint textPain, Paint shadowPaint) {
canvas.drawText(text, x - 1, y, shadowPaint);
canvas.drawText(text, x, y + 1, shadowPaint);
canvas.drawText(text, x + 1, y, shadowPaint);
canvas.drawText(text, x, y - 1, shadowPaint);
canvas.drawText(text, x, y, textPain);
}
/**
* Draw a text with a nice shadow centered in the X axis
*
* #param canvas
* #param text
* #param y
* #param textPain
* #param shadowPaint
*/
public static void drawCentered(Canvas canvas, String text, float y,
Paint textPain, Paint shadowPaint) {
float posx = (canvas.getWidth() - textPain.measureText(text)) / 2;
drawTextShadowed(canvas, text, posx, y, textPain, shadowPaint);
}
/**
* Draw debug info
*
* #param canvas
*/
private void drawDebug(Canvas canvas) {
float posX = 10;
float posY = 20;
Paint paint = new Paint();
paint.setStrokeWidth(5);
paint.setStyle(Style.STROKE);
paint.setColor(Color.BLACK);
canvas.drawCircle(mOrigin.x, mOrigin.y, getWidth(), paint);
paint.setStrokeWidth(3);
paint.setColor(Color.RED);
canvas.drawCircle(mOrigin.x, mOrigin.y, getWidth(), paint);
paint.setStrokeWidth(5);
paint.setColor(Color.BLACK);
canvas.drawLine(mOrigin.x, mOrigin.y, mMovement.x, mMovement.y, paint);
paint.setStrokeWidth(3);
paint.setColor(Color.RED);
canvas.drawLine(mOrigin.x, mOrigin.y, mMovement.x, mMovement.y, paint);
posY = debugDrawPoint(canvas, "A", mA, Color.RED, posX, posY);
posY = debugDrawPoint(canvas, "B", mB, Color.GREEN, posX, posY);
posY = debugDrawPoint(canvas, "C", mC, Color.BLUE, posX, posY);
posY = debugDrawPoint(canvas, "D", mD, Color.CYAN, posX, posY);
posY = debugDrawPoint(canvas, "E", mE, Color.YELLOW, posX, posY);
posY = debugDrawPoint(canvas, "F", mF, Color.LTGRAY, posX, posY);
posY = debugDrawPoint(canvas, "Mov", mMovement, Color.DKGRAY, posX,
posY);
posY = debugDrawPoint(canvas, "Origin", mOrigin, Color.MAGENTA, posX,
posY);
posY = debugDrawPoint(canvas, "Finger", mFinger, Color.GREEN, posX,
posY);
// Draw some curl stuff (Just some test)
/*
* canvas.save(); Vector2D center = new
* Vector2D(getWidth()/2,getHeight()/2);
* //canvas.rotate(315,center.x,center.y);
*
* // Test each lines //float radius = mA.distance(mD)/2.f; //float
* radius = mA.distance(mE)/2.f; float radius = mA.distance(mF)/2.f;
* //float radius = 10; float reduction = 4.f; RectF oval = new RectF();
* oval.top = center.y-radius/reduction; oval.bottom =
* center.y+radius/reduction; oval.left = center.x-radius; oval.right =
* center.x+radius; canvas.drawArc(oval, 0, 360, false, paint);
* canvas.restore(); /*
*/
}
private float debugDrawPoint(Canvas canvas, String name, Vector2D point,
int color, float posX, float posY) {
return debugDrawPoint(canvas, name + " " + point.toString(), point.x,
point.y, color, posX, posY);
}
private float debugDrawPoint(Canvas canvas, String name, float X, float Y,
int color, float posX, float posY) {
mTextPaint.setColor(color);
drawTextShadowed(canvas, name, posX, posY, mTextPaint, mTextPaintShadow);
Paint paint = new Paint();
paint.setStrokeWidth(5);
paint.setColor(color);
canvas.drawPoint(X, Y, paint);
return posY + 15;
}
}
xml code :
<RelativeLayout
android:id="#+id/game_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.mystictreegames.pagecurl.PageCurlView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/dcgpagecurlPageCurlView1"
android:background="#drawable/facebook">
</com.mystictreegames.pagecurl.PageCurlView>
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_centerVertical="true"
android:text="جوهر كون المرء انه انسان لا يسعى الى الكمال"/>
log error:
FATAL EXCEPTION: main
E/AndroidRuntime(2497): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mystictreegames.pagecurl/com.mystictreegames.pagecurl.StandaloneExample}: android.view.InflateException: Binary XML file line #13: Error inflating class com.mystictreegames.pagecurl.PageCurlView
In the init() of the PageCurlView class, you are inflating R.layout.standalone_example. Objects are added in a circular manner (R.layout.standalone_example has PageCurlView which has R.layout.standalone_example which has ...).
I'm learning about queues in school and an having an issue with one of our labs i believe the issue is here the problem is that it will not erase the circles after reaching 50
public void paint(Graphics g)
{
int incX = 5; // initial x increment for circle locations
int incY = 5; // initial y increment for circle locations
Coord temp = new Coord(0,0);
Queue<Coord> q = new LinkedList<Coord>();
Circle c = new Circle(g,circleSize,incX,incY,TIME_DELAY);
try
{
for(int i = 1; i <= TOTAL_NUM_CIRCLES; i++)
{
if(q.size() >= 50)
{
temp = q.remove();
c.eraseCircle(g,temp.getX(),temp.getY());
}
temp = new Coord(getX(),getY());
q.add(temp);
c.drawCircle(g);
c.hitEdge();
}
}
catch(InterruptedException e){}
}
if you need the whole thing to run or test here is all of it with comments saying what everything is and what I'm trying to do
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
/**
* Creates an instance of the GfxApp class, which uses the Circle class, Coord class, and
* a queue to create a screen saver.
* #param args not used
*/
public class ScreenSaver
{
public static void main(String args[])
{
GfxApp gfx = new GfxApp();
}
}
/**
* Creates a Screen Saver by placing Circle coordinates in a queue
*/
class GfxApp extends JFrame
{
private int circleCount, circleSize;
public static final int TIME_DELAY = 10; // controls the speed
public static final int TOTAL_NUM_CIRCLES = 1000; // controls how long it goes
/**
* Creates a GfxApp with 50 circles with diameter 30
*/
public GfxApp()
{
circleCount = 50;
circleSize = 30;
setSize(800,600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
/**
* Draws a stream of circleCount circles of size circleSize. Uses a queue to erase circles
* at the end of the stream. The total number of circles that will be drawn is 2000.
* #param g the Graphics object
*/
public void paint(Graphics g)
{
int incX = 5; // initial x increment for circle locations
int incY = 5; // initial y increment for circle locations
Coord temp = new Coord(0,0);
Queue<Coord> q = new LinkedList<Coord>();
Circle c = new Circle(g,circleSize,incX,incY,TIME_DELAY);
try
{
for(int i = 1; i <= TOTAL_NUM_CIRCLES; i++)
{
if(q.size() >= 50)
{
temp = q.remove();
c.eraseCircle(g,temp.getY(),temp.getX());
}
temp = new Coord(getX(),getY());
q.add(temp);
c.drawCircle(g);
c.hitEdge();
}
}
catch(InterruptedException e){}
}
}
/**
* A class to represent Circle objects. Circles can be drawn and erased.
*/
class Circle
{
private int tlX; // top-left X coordinate
private int tlY; // top-left Y coordinate
private int incX; // increment movement of X coordinate
private int incY; // increment movement of Y coordinate
private boolean addX; // flag to determine add/subtract of increment for X
private boolean addY; // flag to determine add/subtract of increment for Y
private int size; // diameter of the circle
private int timeDelay; // time delay until next circle is drawn
/**
* Creates a Circle with a specified Graphics, size, x increment, y increment and time delay
*/
public Circle(Graphics g, int s, int x, int y, int td)
{
incX = x;
incY = y;
size = s;
addX = true;
addY = false;
tlX = 400;
tlY = 300;
timeDelay = td;
}
/**
* returns the top left X of this circle
* #return tlX
*/
public int getTLX() { return tlX;}
/**
* returns the top left Y of this circle
* #return tlY
*/
public int getTLY() { return tlY;}
/**
* delays the program for a specified number of miliseconds
* #param n number of miliseconds
*/
public void delay(int n) throws InterruptedException
{
Thread.sleep(n);
}
/**
* draws a blue circle and sets the tlX and tlY for the next drawing
* #param g Graphics object
*/
public void drawCircle(Graphics g) throws InterruptedException
{
g.setColor(Color.blue);
g.drawOval(tlX,tlY,size,size);
delay(timeDelay);
if (addX)
tlX+=incX;
else
tlX-=incX;
if (addY)
tlY+=incY;
else
tlY-=incY;
}
/**
* Randomly sets a new direction for the circle by randomly setting
* the x increment and y increment
*/
public void newData()
{
incX = (int) Math.round(Math.random() * 7 + 5);
incY = (int) Math.round(Math.random() * 7 + 5);
}
/**
* Determines if any of the four edges have been hit, and if so, reverses the
* appropriate flags (addX and addY) and calls newData
*/
public void hitEdge()
{
boolean a = false;
if (tlX < incX)
{
addX = true;
a = true;
}
if (tlX > 800 - (30 + incX))
{
addX = false;
a = true;
}
if (tlY < incY + 30)
{
addY = true;
a = true;
}
if (tlY > 600 - (30 + incY))
{
addY = false;
a = true;
}
if (a)
newData();
}
// add an eraseCircle method
public void eraseCircle(Graphics g, int x, int y)
{
g.setColor(Color.black);
g.drawOval(x,y,size,size);
}
}
// Create a Coord class, so that coordinates of drawn circles can be placed in the queue.
// As coordinates are removed from the queue, circles are erased with eraseCircle.
class Coord
{
private int x;
private int y;
public Coord(int a, int b)
{
x=a;
y=b;
}
public int getX(){return x;}
public int getY(){return y;}
public int setX(int a){x=a; return x;}
public int setY(int b){y=b; return y;}
}
your coordinates are backwards:
-public void eraseCircle(Graphics g, int x, int y)
-c.eraseCircle(g,temp.getY(),temp.getX());
switch around x and y and it should work.
Edit:
Ok so the problem is the x and y in your coords are always 0 so I modified your drawCircle method to return the proper coordinates, and your paint method to store them, so this is what you get:
Paint:
public void paint(Graphics g)
{
int incX = 5; // initial x increment for circle locations
int incY = 5; // initial y increment for circle locations
Coord temp = new Coord(0,0);
Queue<Coord> q = new LinkedList<Coord>();
Circle c = new Circle(g,circleSize,incX,incY,TIME_DELAY);
try
{
for(int i = 1; i <= TOTAL_NUM_CIRCLES; i++)
{
if(q.size() >= 50)
{
temp = q.remove();
c.eraseCircle(g,temp.getX(),temp.getY());
}
temp = new Coord(getX(),getY());
//q.add(temp);
q.add(c.drawCircle(g));
c.hitEdge();
}
}
catch(InterruptedException e){}
}
drawCircle:
/**
* draws a blue circle and sets the tlX and tlY for the next drawing
* #param g Graphics object
* #return
*/
public Coord drawCircle(Graphics g) throws InterruptedException
{
g.setColor(Color.blue);
g.drawOval(tlX,tlY,size,size);
delay(timeDelay);
if (addX)
tlX+=incX;
else
tlX-=incX;
if (addY)
tlY+=incY;
else
tlY-=incY;
return new Coord(tlX, tlY);
}
To determine this I set a breakpoint in the paint method and viewed what temp's values were through eclipses debugger.
I'm trying to begin learning to use Perlin Noise to create a tile map. I'm just beginning so I found some source code online to create an array based on Perlin Noise. So I have an array of good data right now (as far as I know) but I don't understand what kinds of methods can be used to convert this from an array into a tile map.
Does anybody have any examples or sources of any methods to do this?
Here is the code I'm using the generate the array.
package perlin1;
import java.util.Random;
public class ImageWriter {
/** Source of entropy */
private Random rand_;
/** Amount of roughness */
float roughness_;
/** Plasma fractal grid */
private float[][] grid_;
/** Generate a noise source based upon the midpoint displacement fractal.
*
* #param rand The random number generator
* #param roughness a roughness parameter
* #param width the width of the grid
* #param height the height of the grid
*/
public ImageWriter(Random rand, float roughness, int width, int height) {
roughness_ = roughness / width;
grid_ = new float[width][height];
rand_ = (rand == null) ? new Random() : rand;
}
public void initialise() {
int xh = grid_.length - 1;
int yh = grid_[0].length - 1;
// set the corner points
grid_[0][0] = rand_.nextFloat() - 0.5f;
grid_[0][yh] = rand_.nextFloat() - 0.5f;
grid_[xh][0] = rand_.nextFloat() - 0.5f;
grid_[xh][yh] = rand_.nextFloat() - 0.5f;
// generate the fractal
generate(0, 0, xh, yh);
}
// Add a suitable amount of random displacement to a point
private float roughen(float v, int l, int h) {
return v + roughness_ * (float) (rand_.nextGaussian() * (h - l));
}
// generate the fractal
private void generate(int xl, int yl, int xh, int yh) {
int xm = (xl + xh) / 2;
int ym = (yl + yh) / 2;
if ((xl == xm) && (yl == ym)) return;
grid_[xm][yl] = 0.5f * (grid_[xl][yl] + grid_[xh][yl]);
grid_[xm][yh] = 0.5f * (grid_[xl][yh] + grid_[xh][yh]);
grid_[xl][ym] = 0.5f * (grid_[xl][yl] + grid_[xl][yh]);
grid_[xh][ym] = 0.5f * (grid_[xh][yl] + grid_[xh][yh]);
float v = roughen(0.5f * (grid_[xm][yl] + grid_[xm][yh]), xl + yl, yh
+ xh);
grid_[xm][ym] = v;
grid_[xm][yl] = roughen(grid_[xm][yl], xl, xh);
grid_[xm][yh] = roughen(grid_[xm][yh], xl, xh);
grid_[xl][ym] = roughen(grid_[xl][ym], yl, yh);
grid_[xh][ym] = roughen(grid_[xh][ym], yl, yh);
generate(xl, yl, xm, ym);
generate(xm, yl, xh, ym);
generate(xl, ym, xm, yh);
generate(xm, ym, xh, yh);
}
/**
* Dump out as a CSV
*/
public void printAsCSV() {
for(int i = 0;i < grid_.length;i++) {
for(int j = 0;j < grid_[0].length;j++) {
System.out.print(grid_[i][j]);
System.out.print(",");
}
System.out.println();
}
}
/**
* Convert to a Boolean array
* #return the boolean array
*/
public boolean[][] toBooleans() {
int w = grid_.length;
int h = grid_[0].length;
boolean[][] ret = new boolean[w][h];
for(int i = 0;i < w;i++) {
for(int j = 0;j < h;j++) {
ret[i][j] = grid_[i][j] < 0;
}
}
return ret;
}
/** For testing */
public static void main(String[] args) {
ImageWriter n = new ImageWriter(null, 1.0f, 250, 250);
n.initialise();
n.printAsCSV();
}
}
The resulting array is all amounts between 0 and 1.
Again, I'm just looking for how this array can be converted into a tile map.
Any help is appreciated. Thanks
I am making and auto clicker using java.awt.Robot. One of the concerns i have however is the movements aren't very humanlike. Can anyone suggest some changes to my code to make it more human like? Right now it just moves in a straight line.
/**
*
* #param robot The java.awt.Robot being utilized
* #param sx The start x position of the mouse
* #param sy The start y potition of the mouse
* #param ex The end x position of the mouse
* #param ey The end y position of the mouse
* #param speed The speed at which to travel
*/
public void moveMouse(Robot robot, int sx, int sy, int ex, int ey, int speed){
for (int i=0; i<100; i++){
int mov_x = ((ex * i)/100) + (sx*(100-i)/100);
int mov_y = ((ey * i)/100) + (sy*(100-i)/100);
robot.mouseMove(mov_x,mov_y);
robot.delay(speed);
}
}
Update:
I decided to go with an algorithm that makes use of Bézier Curves. It's been a very long time since I implemented the change, but I wanted to post it here just in case people would find it useful in the future. Here is what I ended up with:
public class MouseEvent{
public int getMouseX(){
return MouseInfo.getPointerInfo().getLocation().x;
}
public int getMouseY(){
return MouseInfo.getPointerInfo().getLocation().y;
}
public void moveMouse(int speed, int destX, int destY, int ranX, int ranY){
Mouse.moveMouse(new Robot(), new Point(getMouseX(),getMouseY()), new Point(destX, destY), speed, ranX, ranY);
}
}
public class Mouse {
public static void moveMouse(Robot robot, Point s, Point e, int speed, int ranX, int ranY){
if(Math.abs(e.x-s.x) <= ranX && Math.abs(e.y-s.y) <= ranY)
return;
Point[] cooardList;
double t; //the time interval
double k = .025;
cooardList = new Point[4];
//set the beginning and end points
cooardList[0] = s;
cooardList[3] = new Point(e.x+random(-ranX,ranX),e.y+(random(-ranY,ranY)));
int xout = (int)(Math.abs(e.x - s.x) /10);
int yout = (int)(Math.abs(e.y - s.y) /10);
int x=0,y=0;
x = s.x < e.x
? s.x + ((xout > 0) ? random(1,xout) : 1)
: s.x - ((xout > 0) ? random(1,xout) : 1);
y = s.y < e.y
? s.y + ((yout > 0) ? random(1,yout) : 1)
: s.y - ((yout > 0) ? random(1,yout) : 1);
cooardList[1] = new Point(x,y);
x = e.x < s.x
? e.x + ((xout > 0) ? random(1,xout) : 1)
: e.x - ((xout > 0) ? random(1,xout) : 1);
y = e.y < s.y
? e.y + ((yout > 0) ? random(1,yout) : 1)
: e.y - ((yout > 0) ? random(1,yout) : 1);
cooardList[2] = new Point(x,y);
double px = 0,py = 0;
for(t=k;t<=1+k;t+=k){
//use Berstein polynomials
px=(cooardList[0].x+t*(-cooardList[0].x*3+t*(3*cooardList[0].x-
cooardList[0].x*t)))+t*(3*cooardList[1].x+t*(-6*cooardList[1].x+
cooardList[1].x*3*t))+t*t*(cooardList[2].x*3-cooardList[2].x*3*t)+
cooardList[3].x*t*t*t;
py=(cooardList[0].y+t*(-cooardList[0].y*3+t*(3*cooardList[0].y-
cooardList[0].y*t)))+t*(3*cooardList[1].y+t*(-6*cooardList[1].y+
cooardList[1].y*3*t))+t*t*(cooardList[2].y*3-cooardList[2].y*3*t)+
cooardList[3].y*t*t*t;
robot.mouseMove((int)px, (int)py);
robot.delay(random(speed,speed*2));
}
}
}
public void moveMouse(int sx, int sy, int ex, int ey, int speed) throws AWTException {
Robot robot = new Robot();
int a = 10;
boolean flag = true;
for (int i = 0; i < 100; i++) {
int mov_x = ((ex * i) / 100) + (sx * (100 - i) / 100);
int mov_y = ((ey * i) / 100) + (sy * (100 - i) / 100);
if (flag == true) {
robot.mouseMove(mov_x + a, mov_y); // adds 10 to X-axis
flag = false;
} else {
robot.mouseMove(mov_x - 2 * a, mov_y); // subtracts 20 to X-axis
flag = true;
}
robot.delay(speed);
}
}
Just manipulated your code. This moves the mouse in straight path in X-direction. You can achieve what you want from here. Just get the ideas. You can move any way you want if you can manipulate mov_x and mov_y .
You could use Catmull-Rom method. Generate random controlpoints somewhere around the endpoints and maybe where the straight line would be, asking for coordinates on every step moving from start to end (parameter t, from zero to one).
See demo applets and source: http://www.cse.unsw.edu.au/~lambert/splines/