I've been having some problems using Transform.Rotate in dart/Flutter.
I have set up my code so that I can rotate an image with gestures. However once I've rotated the image once and let go and continue the rotation the image is reset back to its original position.
It's the same issue shown here: Rotation gesture produces undesired rotation
The solution here is to save the transform in a variable. Is there any way to save the transform in a variable in Dart/Flutter?
Also the ideal situation would be that I can animate the rotation a little so it's delayed slightly because right now it responds straight away to rotation. If this part is unclear please let me know!!
Any suggestions are welcome!!!
You basically want to save the state of the widget so I think you will need to wrap it in a StatefulWidget to be able to do that.
(https://www.youtube.com/watch?v=AqCMFXEmf3w)
To smooth out the animation you could maybe try and use the AnimatedContainer?
I haven't used it myself but I think it should be what you need! (https://www.youtube.com/watch?v=yI-8QHpGIP4)
EDIT
Okay, I've got it working for you.
Offset vector;
double startingAngle;
double deltaAngle = 0.0;
double finalAngle = 0.0;
// store the final angle of the object
double finalObjectAngle = 0.0;
void _onPanStart(DragStartDetails details) {
_polarCoordFromGlobalOffset(details.globalPosition);
startingAngle = vector.direction;
print('START = $startingAngle ===================================');
}
void _onPanUpdate(DragUpdateDetails details) {
_polarCoordFromGlobalOffset(details.globalPosition);
setState(() {
// HERE you should use the finalObjectAngle
deltaAngle = vector.direction - startingAngle + finalObjectAngle;
finalAngle = deltaAngle;
});
}
void _onPanEnd(DragEndDetails details) {
finalAngle = deltaAngle;
// Save the finalAngle of the object
finalObjectAngle = finalAngle;
print('End = $finalAngle ===================================');
}
Related
I'm creating a Android game with Unity and I'm trying to make an object to follow my finger. This is the code I'm using.
for (int i = 0; i < Input.touchCount; i++)
{
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.touches[i].position), Vector2.zero);
Vector3 touchPosition = Camera.main.ScreenToWorldPoint(Input.touches[i].position);
if (Input.GetTouch(i).phase == TouchPhase.Moved && hit.collider != null)
{
transform.position = new Vector2(touchPosition.x, touchPosition.y + sizeY);
}
}
I put the collider bellow the object and I added the size of the object to the Y, so it appears above my finger.
The problem is that if I move my finger slightly faster, I lose the object, that stays behind. Since the object lags behind, if I move my finger faster I end up out of the collider area and the object just stop moving.
The only way I found that works is to get rid of the Raycast thing and make the object follow the touch anywhere in the screen (I don't like that).
I just want to know if this is the best I can get from Unity and Android or if there a is way to make an object follow the finger in a one-by-one movement, with precision, without lag.
I'm testing on a Samsung Galaxy S8 just with the object and nothing else.
You are not alone with this issue. Unity's Input API is frame-rate based and may not keep with the speed of the touch movement on the screen. If you're working on something that requires fast response based on the touch on the screen, use the new Unity's InputSystem. This API is still in experimental mode.
Its Touchscreen class can be used to access the touch on the screen. Your current code should translate into something like below:
public int touchIndex = 0;
void Update()
{
Touchscreen touchscreen = UnityEngine.Experimental.Input.Touchscreen.current;
if (touchscreen.allTouchControls[touchIndex].ReadValue().phase != PointerPhase.None &&
touchscreen.allTouchControls[touchIndex].ReadValue().phase == PointerPhase.Moved)
{
Vector2 touchLocation = touchscreen.allTouchControls[touchIndex].ReadValue().position;
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(touchLocation), Vector2.zero);
Vector3 touchPosition = Camera.main.ScreenToWorldPoint(touchLocation);
transform.position = new Vector2(touchPosition.x, touchPosition.y + sizeY);
}
}
I am trying to make the following camera panning js script, to work as it should, meaning panning the camera left and right. What I have accomplished till now, is to move camera only left and back to its starting position. I can't get it move left and right on a gui.button being clicked/touched.
Here is the js script:
#pragma strict
var target : GameObject;
var xpositionLeft = 10;
var xpositionRight = -10;
//var smooth : float = 5; // Don't know where should I put this var to make it pan smooth?
private static var isPanning = false;
function Update()
{
if(isPanning == true)
{
transform.position.x = target.transform.position.x;
transform.position.x = xpositionLeft;
}
else
{
transform.position.x = target.transform.position.x; // It only pan the camera left, not right!
transform.position.x = xpositionRight;
}
}
static function doPanning ()
{
isPanning = !isPanning;
}
Can someone give a clue on how to make this script work? I'm new to Unity and programming, so any help is more than welcomed.
Thank you all in advance for your time, and your answers.
There are several problems with your code. First, the lines transform.position.x = target.transform.position.x; don't have any effect, because you're immediately overwriting it in the next line. Your code basically only flips transform.position.x between -10 and 10.
Second, the behavior you expect doesn't match the logic in your code. You have only two states, isPanning true and false, but you need three states: pan left, pan right and do nothing.
// how far the camera should move witch each click
var xPositionOffset = 10;
// -1 = left, 0 = do dothing, 1 = right
var panDirection = 0;
function Update()
{
if (panDirection != 0) // pan left/right
{
transform.position.x = transform.position.x + (panDirection * xPositionOffset);
panDirection = 0;
}
}
Now you only need to set the variable panDirection to -1 or 1 if one your buttons is pressed and the camera will move farther to that side.
If you're having trouble with the vector arithmetic, have a look at the chapter 'Understanding Vector Arithmetic' from the Unity manual.
The above code will move the camera not very smooth, but it's easier to understand the basic concept this way. You can use the function Vector3.MoveTowards to get a smoother movement and the example showed in the linked reference should help you to implement it.
Hey guys so I've been trying to solve this for awhile I have looked on many forums and tried to understand what they were trying to convey with the code using ActionScript 3 but i still get nothing. My main goal is to have a character on stage named "mainPlayer" now i want to set up touch events so that when the user drages his finger up down or side to side i want to the mainPlayer to follow the users path or if the user touches a point on the screen and holds his finger there the mainPlayer will be attracted to the touch and move to the point where the finger is currently at on the screen.
Ive seen lots of stuff with Phase and ID implemented but dont really understand whats going on
so far this is what i have set up:
public class realmEngine extends MovieClip
{
//MultiTouch gestures
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
Multitouch.inputMode = MultitouchInputMode.GESTURE;
public var mainPlayer:mcPlayer;
//PlayerControls
private var speed:Number = 8.0;
public var vx:Number = 0;
public var vy:Number = 0;
private var friction:Number = 0.85;
private var maxSpeed:Number = 15;
public function realmEngine()
{
//Add Player to Stage
mainPlayer = new mcPlayer();
stage.addChild(mainPlayer);
mainPlayer.x = (stage.stageWidth / 2) - 300;
mainPlayer.y = (stage.stageHeight / 2 );
//trace("this works");
//Setup Touch Event listeners
mainPlayer.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
stage.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
stage.addEventListener(TouchEvent.TOUCH_END, onTouchEnd);
//Game Loop Event Listener
stage.addEventListener(Event.ENTER_FRAME, gameLoop);
}
private function gameLoop(e:Event):void
{
mainPlayerControls();
}
private function mainPlayerControls():void
{
}
private function onTouchEnd(e:TouchEvent):void
{
}
private function onTouchMove(e:TouchEvent):void
{
}
private function onTouchBegin(e:TouchEvent):void
{
}
}
I'm not sure what to do inside the onTouch Functions in order for the object that i add to stage by Code to follow the users touch on the screen.
Can anyone lead my in the right direction or give me any advice? I woudld really appreciate it thanks guys
Yes I happen to know how to do this, I just wasn't sure if I had grasped fully what you wanted to achieve.
Note that I won't be taking into account the speed and maxSpeed variables for moving the player. It's beyond this scope and beyond the scope of the top of my head. A little bit of internet searching will get you far on that subject however!
First of all, in order to make the object follow a path drawn by the user, we need a way to store the path. For this, I suggest a Vector with Point as its datatype. It's fast and easy to work with when adding and removing elements without having to worry about its length.
We also need a way to tell wether the player sprite should move or not, in other words wether the user is pressing the finger on the screen or not.
private var _pathPoints : Vector.<Point>;
private var _isMoving : Boolean = false;
Easy-cakes. Now for the fun part!
First, we need to change the scope of the onTouchBegin event, from mainPlayer to the stage. If we don't, the user won't be able to touch an abstract point on the stage and get the player sprite to move there. Simply done with a change to
mainPlayer.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
Then we take care of when the user moves his or her finger. Nothing fancy going on here.
We're just simply storing the coordinates in our vector and storing the current state of wether the user is pressing the screen or not.
private function onTouchBegin ( e:TouchEvent ) : void
{
_pathPoints.push( new Point( e.stageX, e.stageY ) );
_isMoving = true;
}
private function onTouchMove ( e:TouchEvent ) : void
{
_pathPoints.push( new Point( e.stageX, e.stageY ) );
}
private function onTouchEnd ( e:TouchEvent ) : void
{
// Dirty but quick way of clearing the vector
_pathPoints.splice(0);
_isMoving = false;
}
Finally, for the even funnier part; the main game loop! Or "Where the Magic Happens".
private function mainPlayerControls () : void
{
// Update player position and forces
vx *= friction;
vy *= friction;
mainPlayer.x += vx;
mainPlayer.y += vy;
// Check if the player should be moving to a new point
if( _isMoving )
{
// Get a reference to the current target coordinate
var target : Point = _pathPoints[0];
// Check if the player position has reached the current target point
// We use a bounding box with dimensions equal to max speed to ensure
// that the player doesn't move across the point, move back towards it
// and start jojo-ing back and forth
if(mainPlayer.x >= target.x - maxSpeed && mainPlayer.x <= target.x + maxSpeed &&
mainPlayer.y >= target.y - maxSpeed && mainPlayer.y <= target.y)
{
// The player has reached its target
//so we remove the first element of the vector
_pathPoints.shift();
// and update the target reference
target = _pathPoints[0];
}
// Calculate velocities to the first element of the vector
vx = mainPlayer.x - target.x;
vy = mainPlayer.y - target.y;
}
}
I am using a customised version of the mapview (OSMDroid version).
I am using custom tiles within it and I only want the user to be able to view the area where I have my custom tiles.
Is there a way to set the boundary lat longs so when they pan the map it doesn't go past these boundaries?
Update: I know this is an old question, but osmdroid now has a setScrollableAreaLimit() method that will achieve what you are looking for. There is also a setMinZoomLevel() and setMaxZoomLevel() method to easily restrict zoom levels.
Original answer:
Please keep an eye on:
http://code.google.com/p/osmdroid/issues/detail?id=209
A patch has already been created, and will likely be integrated shortly.
This is cross-posted from the osmdroid thread. There's now lists a BoundedMapView class, which implements the afortementioned patch.
For those of use using the .jar or otherwise not that familiar with
patches, I cobbled together a subclass of MapView that supports
limiting the user's view to a specific area.
Details on how to use it,
if not obvious, can be found at
http://www.sieswerda.net/2012/08/15/boundedmapview-a-mapview-with-limits/
Incase it helps anyone....
I have sort of a solution that I am using, it works ok, but could definitely be better as the map can go abit too far off the screen before it jumps back!
It uses the lat longs and works out where the map is, I set 4 coordinates which are roughly the 4 corners of the map I have found it works better if you set them slightly into the map rather exactly the corners, I then work out if the lat longs have left the screen completely.. if so it will bounce it halfway back:
I overrode the mapview and the OnTouch event of the map
#Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_UP) {
// (only works for north of equator)
// * map right side (lat) can't go past the left (lat) of screen
// get geopoints of the 4 corners of the screen
Projection proj = getProjection();
GeoPoint screenTopLeft = proj.fromPixels(0, 0);
GeoPoint screenTopRight = proj.fromPixels(getWidth(), 0);
GeoPoint screenBottomLeft = proj.fromPixels(0, getHeight());
double screenTopLat = screenTopLeft.getLatitudeE6() / 1E6;
double screenBottomLat = screenBottomLeft.getLatitudeE6() / 1E6;
double screenLeftlong = screenTopLeft.getLongitudeE6() / 1E6;
double screenRightlong = screenTopRight.getLongitudeE6() / 1E6;
double mapTopLat = BoundsTopLeftCorner.getLatitudeE6() / 1E6;
double mapBottomLat = BoundsBottomLeftCorner.getLatitudeE6() / 1E6;
double mapLeftlong = BoundsTopLeftCorner.getLongitudeE6() / 1E6;
double mapRightlong = BoundsTopRightCorner.getLongitudeE6() / 1E6;
// screen bottom greater than map top
// screen top less than map bottom
// screen right less than map left
// screen left greater than map right
boolean movedLeft = false;
boolean movedRight = false;
boolean movedUp = false;
boolean movedDown = false;
boolean offscreen = false;
if (screenBottomLat > mapTopLat) {
movedUp = true;
offscreen = true;
}
if (screenTopLat < mapBottomLat) {
movedDown = true;
offscreen = true;
}
if (screenRightlong < mapLeftlong) {
movedLeft = true;
offscreen = true;
}
if (screenLeftlong > mapRightlong) {
movedRight = true;
offscreen = true;
}
if (offscreen) {
// work out on which plane it's been moved off screen (lat/lng)
if (movedLeft || movedRight) {
double newBottomLat = screenBottomLat;
double newTopLat = screenTopLat;
double centralLat = newBottomLat
+ ((newTopLat - newBottomLat) / 2);
if (movedRight)
this.getController().setCenter(
new GeoPoint(centralLat, mapRightlong));
else
this.getController().setCenter(
new GeoPoint(centralLat, mapLeftlong));
}
if (movedUp || movedDown) {
// longs will all remain the same
double newLeftLong = screenLeftlong;
double newRightLong = screenRightlong;
double centralLong = (newRightLong + newLeftLong) / 2;
if (movedUp)
this.getController().setCenter(
new GeoPoint(mapTopLat, centralLong));
else
this.getController().setCenter(
new GeoPoint(mapBottomLat, centralLong));
}
}
}
return super.onTouchEvent(ev);
}}
A few things I should point out if you are considering using this:
I make no guarentees that it will work for your situation and you should only use it as a starting point.
It will only work for areas north of the equator (I think) due to the way I've done the coords!
It works on the "action up" of the touch event, so it takes the point where the user takes their finger off the screen. This means when the map flings it's completely inaccurate as I could not work out where the map stopped, because of this I turned off the fling by overriding the fling event and not doing anything in it.. this does make the map a bit jolty!
If anyone has any better solutions or can improve my code please feel free!
I'm looking for exactly the same thing.
My best lead is to add an Overlay, which extends boolean onScroll(...). If this returns true, then the scroll is cancelled.
This is exactly how I want it, except for one thing: flinging/flicking. The same approach can be used to cancel fling events, though you only get to hear about it at the start of the fling.
Ideally, you'd be able to listen to the computeScroll() method, and limit the (x, y) of the scroll, based on mScroller.getCurX() and mScroller.getCurY().
Problem seemed very simple to me at first but now I am stuck.
Scenario
I want to move a image on the screen, on a certain path I create. Moving this image is being made on a thread, something like:
#Override
public void run() {
Canvas c;
while (run) {
c = null;
try {
c = panel.getHolder().lockCanvas(null);
synchronized (panel.getHolder()) {
panel.updateImageCoordinates();
panel.onDraw(c);
}
} finally {
if (c != null) {
panel.getHolder().unlockCanvasAndPost(c);
}
}
}
for the Image I want to move I have a List with main points where it should go. Each coordinate has:
public class Coordinates {
private int x = 0;
private int y = 0;
private int speedX=0;
private int speedY=0;
}
For example, my first point is -5;-30 and I need to get to second point 50.50. The calculation of next coordinates to draw the image is made on updateImageCoordinates(). My problem is that I don't know how to calculate speedX and speedY so that I get from point A to point B on a straight line. Basically for each execution of updateImageCoorindates() I need to do:
image.currentX= image.currentX+speedX;
image.currentY= image.currentY+speedY
//Check if I reached the B point. if so, move to next point.
I don't know based on knowing the coordinates, how I can calculate the speed on x and Y directions.
I attach a image for exemplification. Any help is appreciated.
I'm not shure if I've understood your question clearly...
If you are looking for function which will translate PointA into point on line A-B.
Line containing both points will have equation:
-30 = -5*a + b
and
50 = 50*a + b
so
b = -250/11
a = 16/11
so to find next point you have to:
check if x of next point is at left (-1) or right (+1) of the destination point
and calculate next point by:
image.currentX= image.currentX+((-1 or +1)*movement_speed);
image.currentY= image.currentY+16/11*(-1 or +1)*movement_speed + (-250/11)
You'll find the API Demos for Animation useful I think. In particular, check out Custom Evaluator.