I need to be able to interact with a representation of a cilinder that has many different parts in it. When the users taps over on of the small rectangles, I need to display a popover related to the specific piece (form).
The next image demonstrates a realistic 3d approach. But, I repeat, I need to solve the problem, the 3d is NOT required (would be really cool though). A representation that complies the functional needs will suffice.
The info about the parts to make the drawing comes from an API (size, position, etc)
I dont need it to be realistic really. The simplest aproximation would be to show a cilinder in a 2d representation, like a rectangle made out of interactable small rectangles.
So, as I mentioned, I think there are (as I see it) two opposite approaches: Realistic or Simplified
Is there a way to achieve a nice solution in the middle? What libraries, components, frameworks that I should look into?
My research has led me to SceneKit, but I still dont know if I will be able to interact with it. Interaction is a very important part as I need to display a popover when the user taps on any small rectangle over the cylinder.
Thanks
You don't need any special frameworks to achieve an interaction like this. This effect can be achieved with standard UIKit and UIView and a little trigonometry. You can actually draw exactly your example image using 2D math and drawing. My answer is not an exact formula but involves thinking about how the shapes are defined and break the problem down into manageable steps.
A cylinder can be defined by two offset circles representing the end pieces, connected at their radii. I will use an orthographic projection meaning the cylinder doesn't appear smaller as the depth extends into the background (but you could adapt to perspective if needed). You could draw this with CoreGraphics in a UIView drawRect.
A square slice represents an angle piece of the circle, offset by an amount smaller than the length of the cylinder, but in the same direction, as in the following diagram (sorry for imprecise drawing).
This square slice you are interested in is the area outlined in solid red, outside the radius of the first circle, and inside the radius of the imaginary second circle (which is just offset from the first circle by whatever length you want the slice).
To draw this area you simply need to draw a path of the outline of each arc and connect the endpoints.
To check if a touch is inside one of these square slices:
Check if the touch point is between angle a from the origin at a.
Check if the touch point is outside the radius of the inside circle.
Check if the touch point is inside the radius of the outside circle. (Note what this means if the circles are more than a radius apart.)
To find a point to display the popover you could average the end points on the slice or find the middle angle between the two edges and offset by half the distance.
Theoretically, doing this in Scene Kit with either SpriteKit or UIKit Popovers is ideal.
However Scene Kit (and Sprite Kit) seem to be in a state of flux wherein nobody from Apple is communicating with users about the raft of issues folks are currently having with both. From relatively stable and performant Sprite Kit in iOS 8.4 to a lot of lost performance in iOS 9 seems common. Scene Kit simply doesn't seem finished, and the documentation and community are both nearly non-existent as a result.
That being said... the theory is this:
Material IDs are what's used in traditional 3D apps to define areas of an object that have different materials. Somehow these Material IDs are called "elements" in SceneKit. I haven't been able to find much more about this.
It should be possible to detect the "element" that's underneath a touch on an object, and respond accordingly. You should even be able to change the state/nature of the material on that element to indicate it's the currently selected.
When wanting a smooth, well rounded cylinder as per your example, start with a cylinder that's made of only enough segments to describe/define the material IDs you need for your "rectangular" sections to be touched.
Later you can add a smoothing operation to the cylinder to make it round, and all the extra smoothing geometry in each quadrant of unique material ID should be responsive, regardless of how you add this extra detail to smooth the presentation of the cylinder.
Idea for the "Simplified" version:
if this representation is okey, you can use a UICollectionView.
Each cell can have a defined size thanks to
collectionView:layout:sizeForItemAtIndexPath:
Then each cell of the collection could be a small rectangle representing a
touchable part of the cylinder.
and using
collectionView:(UICollectionView *)collectionView
didSelectItemAtIndexPath:(NSIndexPath *)indexPath
To get the touch.
This will help you to display the popover at the right place:
CGRect rect = [collectionView layoutAttributesForItemAtIndexPath:indexPath].frame;
Finally, you can choose the appropriate popover (if the app has to work on iPhone) here:
https://www.cocoacontrols.com/search?q=popover
Not perfect, but i think this is efficient!
Yes, SceneKit.
When user perform a touch event, that mean you knew the 2D coordinate on screen, so your only decision is to popover a view or not, even a 3D model is not exist.
First, we can logically split the requirement into two pieces, determine the touching segment, showing right "color" in each segment.
I think the use of 3D model is to determine which piece of data to show in your case if I don't get you wrong. In that case, the SCNView's hit test method will do most of work for you. What you should do is to perform a hit test, take out the hit node and the hit's local 3D coordinate of this node, you can then calculate which segment is hit by this touch and do the decision.
Now how to draw the surface of the cylinder would be the only left question, right? There are various ways to do, for example simply paint each image you need and programmatically and attach it to the cylinder's material or have your image files on disk and use as material for the cylinder ...
I think the problem would be basically solved.
I have a game with a character that can cast fire balls. Right now in my game, when I tap anywhere on the screen, I shoot a fireball at my touch point. For this fireball I'm using an SKEmitterNode where I've created a fireball particle emitter.
The problem I'm running into is, my fireball has an angle set already, but I want that angle to change based on where I tap, so that the trailing flames are behind the fireball, not going up or down or whatever I've set it to in the sks file.
I've never done something like this, is there something built into swift already for calculating angles? I can't find much on google
There are two options:
1) first one is that you can use :
fireBall.moveTo(touchLocation.x, touchLocation.y)
function so you can avoid use angles (if I understand you correctly). touchLocation is CGPoint of location of the touch event.
2) second one use as it was said before you will get an angle:
atan2(deltaY,deltaX)
I searched this on the internet but I still haven't found the answer I wanted.
So, I have a 2d tiled game and each tiles position is a multiple of 1.25 for example 7.5, 3.75. There is going to be a player walking on top it and i want to control the player by dragging it and if you release the touch it would be perfectly on a tile instead of in between the tiles. Right now, I can't even figure out how to drag the gameObject with touch. Can anyone help me and explain to me how to do that?
You need to have a collider on every object you plan to move. Then create a class whose sole purpose is to fire a Raycast. Detect when a touch happens. Then fire the Raycast.
RaycastHit hit;
if(Physics.Raycast(ray, out hit, 100))
Debug.DrawLine(ray.origin, hit.point);
You will notice that you have what you hit; with that you can send a message to that particular object.
hit.collider.SendMessage("move");
Inside the object that you hit, you now have to use the coordinates of the touch position to update the transform.position.
I'm bulding a simple application using SpriteKit for iOS 7 / 8 but I'm having some issues with my sprites when I try to touch and launch some events from one of two nodes that are too close to each other.
When I try to touch one of them, I end up touching the upper layer one square mask, and if I change the [self addChaild:] order it happens the same but with the other one.
I want to know if I can create a more precisse mask for my nodes so this won happen when I try to touch them. I know I can create a physics world and a physics body for each of them to control Collision Detection but I don't know if this is the right approach.
BTW... I'm using the methods touchesBegan:withEvent: and touchesEnded:withEvent: for touching events detection.
PD: if you need any more info about my implementation please let me know.
When I touch a UIView with the base of my finger tip, and get the touch point using touches anyObject, I get a single touch point, even though the base of my finger tip has an area that touches a lot many points. Is there a way to get all those points? If there is no such way, how are simple paint apps implemented in ios?
You are getting the only point / touch. Each touch is related to a single finger. This is controlled by iOS.
'Simple' drawing / painting apps use the path traced by the touch points together with the current line drawing width and texture to create lines or bezier paths.
If you're trying to create a drawing app with some form of pressure sensitivity then you'd need to integrate with a 3rd party stylus (like this one)