Keep moving images bouncing within frame width and height - ios

I am trying to figure out how to keep an image within the frame width and height. Right now it just wraps around. I would preferably like to create something that stays within the frame and bounces around inside.
-(void) moveButterfly {
bfly.center = CGPointMake(bfly.center.x + bfly_vx, bfly.center.y + bfly_vy);
if(bfly.center.x > frameWidth)
{
bfly.center = CGPointMake(0, bfly.center.y + bfly_vy);
}
else if (bfly.center.x < 0)
{
bfly.center = CGPointMake(frameWidth, bfly.center.y + bfly_vy);
}
if(bfly.center.y > frameHeight)
{
bfly.center = CGPointMake(bfly.center.x + bfly_vx, 0);
}
else if (bfly.center.y < 0)
{
bfly.center = CGPointMake(bfly.center.x + bfly_vx, frameHeight);
}
}

-(void)moveButterfly{
static int dx = 1;
static int dy = 1;
if (bfly.frame.origin.x >= self.view.bounds.size.width - bfly.bounds.size.width) {
dx = -dx;
}
if (bfly.frame.origin.y >= self.view.bounds.size.height - bfly.bounds.size.height) {
dy = -dy;
}
if (bfly.frame.origin.x <= 0) {
dx = -dx;
}
if (bfly.frame.origin.y <= 0) {
dy = -dy;
}
CGPoint point = bfly.center;
point.x += dx;
point.y += dy;
bfly.center = point;
}
Keep Calling this function using NSTimer at the rate you want to update position. Here dx and dy is the velocity at which butterfly will move.

Related

Zooming in on a UI element causes it to become unsharp/pixelated on iOS

I am using Xamarin.Forms.
On iOS, when using the pinch gesture below to zoom in on a Label (for example), the Label turns pixelated instead of updating and staying sharp.
On Android, this doesn't happen and the Label stays sharp and visible, no matter how much I zoom in on it.
Is there a way to make behave on iOS as it does with Android?
Edit: this behaviour can also be observed simply by raising the scale of a visual element, on Android it looks good but on iOS it turns pixelated. I assume my problem lies here but I'm not sure how to tackle it yet.
The pinch gesture implementation I use to zoom in with:
public class ZoomWithPinch : ContentView
{
public ZoomWithPinch()
{
var pinchGesture = new PinchGestureRecognizer();
pinchGesture.PinchUpdated += OnPinchUpdated;
GestureRecognizers.Add(pinchGesture);
}
double currentScale = 1;
double startScale = 1;
double xOffset = 0;
double yOffset = 0;
private void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
{
if (e.Status == GestureStatus.Started)
{
startScale = Content.Scale;
Content.AnchorX = 0;
Content.AnchorY = 0;
}
if (e.Status == GestureStatus.Running)
{
currentScale += (e.Scale - 1) * startScale;
currentScale = Math.Max(1, currentScale);
double renderedX = Content.X + xOffset;
double deltaX = renderedX / Width;
double deltaWidth = Width / (Content.Width * startScale);
double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;
double renderedY = Content.Y + yOffset;
double deltaY = renderedY / Height;
double deltaHeight = Height / (Content.Height * startScale);
double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;
double targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
double targetY = yOffset - (originY * Content.Height) * (currentScale - startScale);
Content.TranslationX = Math.Min(0, Math.Max(targetX, -Content.Width * (currentScale - 1)));
Content.TranslationY = Math.Min(0, Math.Max(targetY, -Content.Height * (currentScale - 1)));
Content.Scale = currentScale;
}
if (e.Status == GestureStatus.Completed)
{
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
}
}
public void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
if (Content.Scale == 1)
{
return;
}
switch (e.StatusType)
{
case GestureStatus.Running:
double newX = (e.TotalX * Scale) + xOffset;
double newY = (e.TotalY * Scale) + yOffset;
double width = (Content.Width * Content.Scale);
double height = (Content.Height * Content.Scale);
bool canMoveX = width > Application.Current.MainPage.Width;
bool canMoveY = height > Application.Current.MainPage.Height;
if (canMoveX)
{
double minX = (width - (Application.Current.MainPage.Width / 2)) * -1;
double maxX = Math.Min(Application.Current.MainPage.Width / 2, width / 2);
if (newX < minX)
{
newX = minX;
}
if (newX > maxX)
{
newX = maxX;
}
}
else
{
newX = 0;
}
if (canMoveY)
{
double minY = (height - (Application.Current.MainPage.Height / 2)) * -1;
double maxY = Math.Min(Application.Current.MainPage.Width / 2, height / 2);
if (newY < minY)
{
newY = minY;
}
if (newY > maxY)
{
newY = maxY;
}
}
else
{
newY = 0;
}
Content.TranslationX = newX;
Content.TranslationY = newY;
break;
case GestureStatus.Completed:
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
break;
}
}
}
<ZoomWithPinch>
<Grid>
<Label Text="Test" HorizontalOptions="Center" VerticalOptions="Center"/>
</Grid>
</ZoomWithPinch>

Change mouse position when I move my player

I've set my camera following my player, but I have a problem.
When my player moves, the vector changes obviously but not my mouse position.
I have to calculate the mouse angles of where I shoot my bullets and directions so it becomes very weird if my mouse position does not change but my vector does.
Really have no idea what to do, even after searching all over the internet.
Code for when I shoot:
v.X = (float)Math.Sqrt((5 * 5) / (1 + ((dy * dy) / (dx * dx))));
v.Y = (float)Math.Sqrt(5 * 5 - v.X * v.X);
if(Mouse.GetState().X > vector.X && Mouse.GetState().Y > vector.Y )
{
bullets.Add(new Bullet(bulletTexture, vector.X, vector.Y, v.X, v.Y, 1));
}
if (Mouse.GetState().X < vector.X && Mouse.GetState().Y > vector.Y)
{
bullets.Add(new Bullet(bulletTexture, vector.X, vector.Y, -v.X, v.Y, 1));
}
if (Mouse.GetState().X > vector.X && Mouse.GetState().Y < vector.Y)
{
bullets.Add(new Bullet(bulletTexture, vector.X, vector.Y, v.X, -v.Y, 1));
}
if (Mouse.GetState().X < vector.X && Mouse.GetState().Y < vector.Y)
{
bullets.Add(new Bullet(bulletTexture, vector.X, vector.Y, -v.X, -v.Y, 1));
}
Player facing where the mouse shoots:
mosAngle = (float)Math.Atan((Mouse.GetState().Y - vector.Y ) / (Mouse.GetState().X - vector.X));
if(Mouse.GetState().LeftButton == ButtonState.Pressed)
{
if (Mouse.GetState().Y < vector.Y && Math.Abs(mosAngle) > Math.PI / 4)
{
texture = backAnim;
}
else if (Mouse.GetState().Y > vector.Y && Math.Abs(mosAngle) > Math.PI / 4)
{
texture = frontAnim;
}
else if (Mouse.GetState().X > vector.X)
{
texture = rightAnim;
}
else
{
texture = leftAnim;
}
Camera class:
class Camera
{
private Matrix transform;
private Viewport view;
private Vector2 centre, camPos;
public Matrix Transform
{
get { return transform; }
}
public Camera(Viewport view)
{
this.view = view;
}
public void Update(GameTime gameTime)
{
KeyboardState keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.D))
{
camPos.X += 2f;
}
if (keyboardState.IsKeyDown(Keys.A))
{
camPos.X -= 2f;
}
if (keyboardState.IsKeyDown(Keys.W))
{
camPos.Y -= 4f;
}
if (keyboardState.IsKeyDown(Keys.S))
{
camPos.Y += 4f;
}
centre = new Vector2(camPos.X, camPos.Y);
transform = Matrix.CreateScale(new Vector3(1, 1, 0)) * Matrix.CreateTranslation(new Vector3(-centre.X, -centre.Y, 0));
}
I'm not sure what I should do in order for the code for shooting and facing the same direction where player shoots to work.
When my player moves, the vector changes obviously but not my mouse position.
That is because the mouse position is always the position within the window and not - like your player - in the game world.
So you need to deal with two different positions like mouseWindowPosition (which you get from your mouseState and mouseWorldPosition which you get by adding the mouseWindowPosition and your camera position.

iOS drag and drop within parent bounds

I'm try to implement drag and drop for some UIImageViews within a UIView. It is currently working, with the exception that you can drag the image views out of the parent and off the screen. I know I have to check to see if the views go outside the parent bounds.. but im struggling to achieve it! Does anyone have any experience with this? For the Windows Phone client, all that is needed is the following line;
var dragBehavior = new MouseDragElementBehavior {ConstrainToParentBounds = true};
The current gesture code I have is here;
private UIPanGestureRecognizer CreateGesture(UIImageView imageView)
{
float dx = 0;
float dy = 0;
var panGesture = new UIPanGestureRecognizer((pg) =>
{
if ((pg.State == UIGestureRecognizerState.Began || pg.State == UIGestureRecognizerState.Changed) && (pg.NumberOfTouches == 1))
{
var p0 = pg.LocationInView(View);
if (dx == 0)
dx = (float)p0.X - (float)imageView.Center.X;
if (dy == 0)
dy = (float)p0.Y - (float)imageView.Center.Y;
float newX = (float)p0.X - dx;
float newY = (float)p0.Y - dy;
var p1 = new PointF(newX, newY);
imageView.Center = p1;
}
else if (pg.State == UIGestureRecognizerState.Ended)
{
dx = 0;
dy = 0;
}
});
return panGesture;
}
I resolved this with the following code;
var panGesture = new UIPanGestureRecognizer((pg) =>
{
if ((pg.State == UIGestureRecognizerState.Began || pg.State == UIGestureRecognizerState.Changed) && (pg.NumberOfTouches == 1))
{
var p0 = pg.LocationInView(View);
if (dx == 0)
dx = (float)p0.X - (float)imageView.Center.X;
if (dy == 0)
dy = (float)p0.Y - (float)imageView.Center.Y;
float newX = (float)p0.X - dx;
float newY = (float)p0.Y - dy;
var p1 = new PointF(newX, newY);
// If too far right...
if (p1.X > imageView.Superview.Bounds.Size.Width - (imageView.Bounds.Size.Width / 2))
p1.X = (float) imageView.Superview.Bounds.Size.Width - (float)imageView.Bounds.Size.Width / 2;
else if (p1.X < 0 + (imageView.Bounds.Size.Width / 2)) // If too far left...
p1.X = 0 + (float)(imageView.Bounds.Size.Width / 2);
// If too far down...
if (p1.Y > imageView.Superview.Bounds.Size.Height - (imageView.Bounds.Size.Height / 2))
p1.Y = (float)imageView.Superview.Bounds.Size.Height - (float)imageView.Bounds.Size.Height / 2;
else if (p1.Y < 0 + (imageView.Bounds.Size.Height / 2)) // If too far up...
p1.Y = 0 + (float)(imageView.Bounds.Size.Height / 2);
imageView.Center = p1;
}
else if (pg.State == UIGestureRecognizerState.Ended)
{
// reset offsets when dragging ends so that they will be recalculated for next touch and drag that occurs
dx = 0;
dy = 0;
}
});

Find the precise centroid (as an MKMapPoint) of an MKPolygon

This means excluding the area(s) of any interiorPolygons.
Once one has the centroid of the outer points polygon, how does one (i.e., in the form of an Objective-C example) adjust the centroid by the subtractive interiorPolygons? Or is there a more elegant way to compute the centroid in one go?
If you help get the code working, it will be open sourced (WIP here).
Might be helpful:
http://www.ecourses.ou.edu/cgi-bin/eBook.cgi?topic=st&chap_sec=07.2&page=case_sol
https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
Thinking about it today, it makes qualitative sense that adding each interior centroid weighted by area to the exterior centroid would arrive at something sensible. (A square with an interior polygon (hole) on the left side would displace the centroid right, directly proportional to the area of the hole.)
Not to scale:
- (MKMapPoint)calculateCentroid
{
switch (self.pointCount) {
case 0: return MKMapPointMake(0.0,
0.0);
case 1: return MKMapPointMake(self.points[0].x,
self.points[0].y);
case 2: return MKMapPointMake((self.points[0].x + self.points[1].x) / 2.0,
(self.points[0].y + self.points[1].y) / 2.0);
}
// onward implies pointCount >= 3
MKMapPoint centroid;
MKMapPoint *previousPoint = &(self.points[self.pointCount-1]); // for i=0, wrap around to the last point
for (NSUInteger i = 0; i < self.pointCount; ++i) {
MKMapPoint *point = &(self.points[i]);
double delta = (previousPoint->x * point->y) - (point->x * previousPoint->y); // x[i-1]*y[i] + x[i]*y[i-1]
centroid.x += (previousPoint->x + point->x) * delta; // (x[i-1] + x[i]) / delta
centroid.y += (previousPoint->y + point->y) * delta; // (y[i-1] + y[i]) / delta
previousPoint = point;
}
centroid.x /= 6.0 * self.area;
centroid.y /= 6.0 * self.area;
// interiorPolygons are holes (subtractive geometry model)
for (MKPolygon *interiorPoly in self.interiorPolygons) {
if (interiorPoly.area == 0.0) {
continue; // avoid div-by-zero
}
centroid.x += interiorPoly.centroid.x / interiorPoly.area;
centroid.y += interiorPoly.centroid.y / interiorPoly.area;
}
return centroid;
}
in Swift 5
private func centroidForCoordinates(_ coords: [CLLocationCoordinate2D]) -> CLLocationCoordinate2D? {
guard let firstCoordinate = coordinates.first else {
return nil
}
guard coords.count > 1 else {
return firstCoordinate
}
var minX = firstCoordinate.longitude
var maxX = firstCoordinate.longitude
var minY = firstCoordinate.latitude
var maxY = firstCoordinate.latitude
for i in 1..<coords.count {
let current = coords[i]
if minX > current.longitude {
minX = current.longitude
} else if maxX < current.longitude {
maxX = current.longitude
} else if minY > current.latitude {
minY = current.latitude
} else if maxY < current.latitude {
maxY = current.latitude
}
}
let centerX = minX + ((maxX - minX) / 2)
let centerY = minY + ((maxY - minY) / 2)
return CLLocationCoordinate2D(latitude: centerY, longitude: centerX)
}

Different x and y speed (acceleration) in cocos2d?

I want to create a visible object with a trajectory using standard actions (CCMoveBy and e.t.c) which is similar to:
x = sin(y)
My code:
CCMoveBy *moveAction1 = [CCMoveBy actionWithDuration:1.5 position:ccp(300, 0)];
CCEaseInOut *easeInOutAction1 = [CCEaseInOut actionWithAction:moveAction1 rate:2];
CCMoveBy *moveAction2 = [CCMoveBy actionWithDuration:1.5 position:ccp(-300, 0)];
CCEaseInOut *easeInOutAction2 = [CCEaseInOut actionWithAction:moveAction2 rate:2];
CCMoveBy *moveAction3 = [CCMoveBy actionWithDuration:1.5 position:ccp(0, -32)];
CCSpawn *moveActionRight = [CCSpawn actionOne:easeInOutAction1 two:moveAction3];
CCSpawn *moveActionLeft = [CCSpawn actionOne:easeInOutAction2 two:moveAction3];
CCSequence *sequenceOfActions = [CCSequence actionOne:moveActionRight two:moveActionLeft];
CCRepeatForever *finalMoveAction = [CCRepeatForever actionWithAction:sequenceOfActions];
[enemy runAction:finalMoveAction];
This code shows move down only. The problem is that object has a different x and y accelerations and I don't know how to combine them
UPDATED
- (void)tick:(ccTime)dt
{
CGPoint pos = self.position;
pos.y -= 50 * dt;
if (pos.y < activationDistance) {
pos.x = 240 + sin(angle) * 140;
angle += dt * 360 * 0.007;
if (angle >= 360) {
angle = ((int)angle) % 360;
}
}
self.position = pos;
}
It is my current solution. I can increase activationDistance to adjust the object trajectory. But I want to setup an initial value of the angle variable.
I use numbers instead of variables because they are used inside this function only.
SOLVED
To change the initial angle:
angle = point.x < 240 ? -asin((240 - point.x) / 140) : asin((point.x - 240) / 140);
the main problem was my tiled map has its own coordinates and cover 320x320 part of the screen only
I think it will be easier for you to just do it in your frame update method (the one I assume you schedule for updating your objects. So why not just do :
- (void)tick:(ccTime)dt {
CGPoint pos = myObject.position;
pos.x = <desired x> + sin(angle);
pos.y = pos.y - y_acceleration * dt;
angle += dt * 360 * x_acceleration;
if (angle >= 360)
angle = ((int)angle) % 360;
myObject.position = pos;
}
And you can apply the same for the y axis of the object

Resources