i am trying to implement a drag and drop behaviour for an object, i need to register when the touch is being pressed and after moving it a bit it should start dragging.
unfortunately i am using a custom framework that is implemented in C# and it's something like XNA.
How would you do it on XNA?
(it's for an android tablet) .
Obviously this example should be refactored to use input services and better handling for the touch up/down concepts, but the core of the answer remains the same:
// I don't remember the exact property names, but you probably understand what I mean
public override void Update(GameTime time)
{
var currentState = TouchPanel.GetState();
var gestures = currentState.TouchGestures;
var oldGests = this.oldState.TouchGestures;
if (oldGests.Count == 0 && gestures.Count == 1 && gestures[0].State == Pressed)
{
// Went from Released to Pressed
this.touchPressed = true;
}
else
{
// Not the frame it went to Pressed
this.touchPressed = false;
}
if (oldGests.Count == 1 && gestures.Count == 1 && oldGests[0].State == Pressed && gestures[0].State == Pressed)
{
// Touch is down, and has for more than 1 frame (aka. the user is dragging)
this.touchDown = true;
}
else
{
this.touchDown = false;
}
if (oldGests.Count == 1 && oldGests[0].State == Pressed && gestures.Count == 0)
{
// Went from Released to Pressed
this.touchReleased = true;
}
else
{
// Not the frame it went to Pressed
this.touchReleased = false;
}
this.oldState = currentState;
}
You might have to fiddle with the 'ifs' a bit, since I don't actually remember if Gestures goes down to 0 the first frame after you release your finger, or if it still shows 1 Gesture called 'Released'. Test it, and you shall have your answer!
Now you can use 'this.touchDown' elsewhere in your code to determine if your object should move or not.
Related
I have been working on a 3D endless runner game for some time when I faced this issue. During sideways movement, after switching each lane, my character just jumps back (-z axis) a couple of decimals which is very noticeable for someone who's playing the game; feeling like he's teleporting backward a few decimals. The issue came up after adding this simple code transform.position = locationAfterChangingLane; which stopped the overflowing of sideways movement. It did stop overflowing but made this annoying bug.
(code line situated in the isChangingLane if statement in update method.)
Here's my script (full, also I have commented where the above code line for easy reference.)
//Variables for Lane switching
private bool isChangingLane = false;
private Vector3 locationAfterChanginLane = Vector3.zero;
private Vector3 sideWayMovementDistance = Vector3.right * 2f; // This might be the case that triggers abnormal movements
private float sideWaySpeed = 6f;
public enum Lane
{
Left,
Right,
Center
}
public enum MoveDirection
{
Left,
Right,
None
}
Lane currentLane = Lane.Center;
void Update()
{
currentBaseState = anim.GetCurrentAnimatorStateInfo(0);
if (controller.isGrounded)
{
verticalVelocity = -0.5f;
if (currentBaseState.fullPathHash == locoState)
{
if (Input.GetButtonDown("Jump"))
{
verticalVelocity = 18f;
anim.SetBool("Jump", true);
}
else if (Input.GetKeyDown(KeyCode.S))
{
anim.SetBool("Slide", true);
}
}
MoveLeftRight(); // This is the method to move right and left.
if (isChangingLane)
{
if (Math.Abs(transform.position.x - locationAfterChanginLane.x) < 0.1f)
{
isChangingLane = false;
moveVector.x = 0;
transform.position = locationAfterChangingLane; // This is the code which throws this issue.
}
}
}
}
private void MoveLeftRight()
{
MoveDirection requestedMoveDirection = MoveDirection.None;
if (Input.GetKeyDown(KeyCode.A) && !isChangingLane)
{
requestedMoveDirection = MoveDirection.Left;
isChangingLane = true;
}
else if (Input.GetKeyDown(KeyCode.D) && !isChangingLane)
{
requestedMoveDirection = MoveDirection.Right;
isChangingLane = true;
}
switch (requestedMoveDirection)
{
case MoveDirection.Right:
if (currentLane == Lane.Right)
{
Debug.Log("Right Lane");
break; //Do nothing when in right lane.
}
else if (currentLane == Lane.Center)
{
locationAfterChanginLane = transform.position + sideWayMovementDistance;
moveVector.x = +sideWaySpeed;
currentLane = Lane.Right;
Debug.Log("Center --> Right");
}
else if (currentLane == Lane.Left)
{
locationAfterChanginLane = transform.position + sideWayMovementDistance;
moveVector.x = +sideWaySpeed;
currentLane = Lane.Center;
Debug.Log("Left --> Center");
}
break;
case MoveDirection.Left:
if (currentLane == Lane.Left)
{
Debug.Log("Left Lane");
break; //Do nothing when in left lane.
}
else if (currentLane == Lane.Center)
{
locationAfterChanginLane = transform.position - sideWayMovementDistance;
moveVector.x = -sideWaySpeed;
currentLane = Lane.Left;
Debug.Log("Center --> Left");
}
else if (currentLane == Lane.Right)
{
locationAfterChanginLane = transform.position - sideWayMovementDistance;
moveVector.x = -sideWaySpeed;
currentLane = Lane.Center;
Debug.Log("Right --> Center");
}
break;
}
}
Help would be greatly appreciated. How do I solve this? Also can you kindly explain why this happens? Many thanks!
It looks like you have a non-instantaneous movement animation as your character changes lane. That's good, but it also looks like you save the destination point at the moment that someone presses left or right. This position is stored in memory, and then about 0.5 sec later when they arrive at that lane fully, it reuses that position - which has stayed behind them.
A quick fix would be, once the lane movement animation has ended, just change locationAfterChangingLane's Z component to match the player's current Z component. Or, instead of saving and setting that vector, apply a Math.Max/Math.Min operation to the player's location so that they don't go past a certain maximum.
Another side note: I've seen some people run into math issues when playing their infinite runner for more than a few minutes because all their numbers are entering high ranges. It's possible that you'd want to consider simply having sections of the world simply "slide past" a still protagonist and be recycled behind him, so that even after 20 minutes of playing he's still at (0, 0, 0)
I am building a paint-like program in processing. I want to be able to adjust the r, g, and b values of the pen color. What I did is use the 'r' key to allow the user to change r. After hitting 'r' they use the '+' and '-' keys to adjust it. Then you hit 'd', and it finishes. '+' and '-' are already used for pen size so I had to do it this way. But when I run the code and hit r it freezes up and stops responding. Does anyone know what is wrong.
Here is the problematic part of the code:
if(key == 'r'){ // Activates if 'r' is pressed
actr = true; // Sets actr = to true
while (actr = true) { // Goes until actr is false
if (key == '=') { // Activates is '=' is pressed
r = r ++; // Increases r by one
}
if (key == '-'){ // Activates if '-' is pressed
r = r --; // Decreases r by one
}
if (key == 'd') { // Activates if 'd' is pressed
actr = false; // Sets actr = to false
}
}
}
Here is the full code: http://www.openprocessing.org/sketch/226658
You've got a few problems. First of all, look at this line:
while (actr = true) { // Goes until actr is false
You're not checking equality here, you're assigning the value of true to your actr variable, which will also evaluate to true. In other words, that will never be false. Instead, you should use:
while (actr == true) {
Or even better:
while (actr) {
However, even when you fix that, your while loop will still never exit. This is because you're busy waiting and blocking the program from continuing. This will prevent Processing from ever changing the key variable.
Instead of busy waiting, just keep track of which mode you're in, which determines what the + and - keys do. You could use a series of booleans:
boolean size = true;
boolean red = false;
boolean green = false;
boolean blue = false;
void keyPressed(){
if(key == 'r'){ // Activates if 'r' is pressed
if (key == '=') {
if(size){
x++;
}
else if(red){
r++;
}
}
else if (key == '-'){
if(size){
x++;
}
else if(red){
r++;
}
}
if (key == 'd') { // Activates if 'd' is pressed
size = true;
red = false;
blue = false;
green = false;
}
else if(key == 'r'){
size = false;
red = true;
blue = false;
green = false;
}
}
}
That's just one approach, and I didn't include all of the code, but that should be a better general idea than your busy waiting.
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 would like to zoom in on an object for as long as I hold the right mouse button down. The issue right now is that I have to click it every time I want to zoom. Is there a way I can modify my code so that it will zoom while I hold the button, rather than clicking it?
void mouse(int button, int state, int x, int y)
{
// Save the left button state
if (button == GLUT_LEFT_BUTTON)
{
leftMouseButtonDown = (state == GLUT_DOWN);
zMovement += 0.1f;
}
else if (button == GLUT_RIGHT_BUTTON)
{
leftMouseButtonDown = (state == GLUT_DOWN);
zMovement -= 0.1f;
}
// Save the mouse position
mouseXPos = x;
mouseYPos = y;
}
The state variable of your function tells you what type of mouse-button event had happened: It can either be GLUT_DOWN or GLUT_UP.
Knowing this, you can store this state in an extra variable outside of the mouse function and zoom as long as the state is set to true (this has to be done somewhere in every frame). The code could look like the following:
void mouse(int button, int state, int x, int y)
{
// Save the left button state
if (button == GLUT_LEFT_BUTTON)
{
leftMouseButtonDown = (state == GLUT_DOWN);
}
else if (button == GLUT_RIGHT_BUTTON)
{
// \/ right MouseButton
rightMouseButtonDown = (state == GLUT_DOWN);
}
// Save the mouse position
mouseXPos = x;
mouseYPos = y;
}
void callThisInEveryFrame()
{
if (leftMouseButtonDown)
zMovement += 0.1f;
if (rightMouseButtonDown)
zMovement -= 0.1f;
}
I'm trying to write a chess game and find that I cannot find solutions to find a stalemate situation. I'm trying to google, but can't find anything. Is there a well-known algorithm or something?
Your move generator will be one of two different designs;
either it checks for legality while generating the moves
or you generate all possible moves and remove those that are illegal afterwards.
The former is better as it doesn't need post-processing.
A stalemate condition is simply one where there are no legal moves and the moving-side's king is not in check. A checkmate condition is one where there are no legal moves but the moving-side's king is in check.
In other words if you've figured out how to detect check and checkmate, you've already got everything necessary to detect stalemate.
Here is an Open-source code with all the rules for the classic Chess game:
https://github.com/cjortegon/basic-chess
You can run the project right after cloning the project (Android, iOS, Desktop and Web), or you can use the main logic, which is here: https://github.com/cjortegon/basic-chess/tree/master/libgdx/core/src/com/mountainreacher/chess/model
I based my solution on a 3-moments algorithm, first moment is when the player selects a piece from the board, then when the destination of this piece has been chosen and finally when the piece reaches that position (considering that it is an animated game, if not, you can merge step 2 and 3).
The following code has been implemented in Java. From the properties of the model class:
boolean turn;
GenericPiece selected, conquest;
ClassicBoard board;
List<int[]> possibleMovements;
int checkType;
The first method will handle moments 1, 2 and the special 'conquest' moment (applied to pawn piece only):
public boolean onCellClick(int row, int column) {
if (row == -1 && conquest != null) {
checkType = 0;
conquest.changeFigure(column);
return true;
} else if (selected != null) {
if (possibleMovements != null) {
for (int[] move : possibleMovements) {
if (move[0] == row && move[1] == column) {
// Move the PieceActor to the desired position
if (selected.moveTo(row, column)) {
turn = !turn;
}
break;
}
}
}
selected = null;
possibleMovements = null;
return true;
} else {
selected = board.getSelected(turn ? Piece.WHITE_TEAM : Piece.BLACK_TEAM, row, column);
if (selected != null) {
possibleMovements = new ArrayList<>();
possibleMovements.addAll(((GenericPiece) selected).getMoves(board, false));
// Checking the movements
board.checkPossibleMovements(selected, possibleMovements);
if (possibleMovements.size() == 0) {
possibleMovements = null;
selected = null;
return false;
} else {
return true;
}
}
}
return false;
}
And the following method will handle the 3rd moment (when animation finishes):
public void movedPiece(Piece piece) {
Gdx.app.log(TAG, "movedPiece(" + piece.getType() + ")");
// Killing the enemy
Piece killed = board.getSelectedNotInTeam(piece.getTeam(),
piece.getRow(), piece.getColumn());
if (killed != null) {
killed.setAvailable(false);
}
// Checking hacks
GenericPiece[] threat = board.kingIsInDanger();
if (threat != null) {
checkType = board.hasAvailableMoves(threat[0].getTeam()) ? CHECK : CHECK_MATE;
} else {
checkType = NO_CHECK;
}
// Checking castling
if (piece.getFigure() == Piece.ROOK && ((GenericPiece) piece).getMovesCount() == 1) {
Piece king = board.getSelected(piece.getTeam(),
piece.getRow(), piece.getColumn() + 1);
if (king != null && king.getFigure() == Piece.KING && ((GenericPiece) king).getMovesCount() == 0) {
// Left Rook
if (board.getSelected(piece.getRow(), piece.getColumn() - 1) == null) {
king.moveTo(piece.getRow(), piece.getColumn() - 1);
}
} else {
king = board.getSelected(piece.getTeam(),
piece.getRow(), piece.getColumn() - 1);
if (king != null && king.getFigure() == Piece.KING && ((GenericPiece) king).getMovesCount() == 0) {
// Right Rook
if (board.getSelected(piece.getRow(), piece.getColumn() + 1) == null) {
king.moveTo(piece.getRow(), piece.getColumn() + 1);
}
}
}
}
// Conquest
else if (piece.getFigure() == Piece.PAWN && (piece.getRow() == 0 || piece.getRow() == board.getRows() - 1)) {
conquest = (GenericPiece) piece;
checkType = CONQUEST;
}
}
That code covers all the rules from the classic chess, including: regular piece movements, castling, check, check-mate and conquests of pawns.