Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

AppGameKit Classic Chat / Pinch Zoom - Free Code and mini tutorial

Author
Message
baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 22nd Apr 2013 13:36 Edited at: 24th Apr 2013 12:50
I just finished working on a game for TGC called “Hide It Find It” and I thought it would be handy to share some useful code and write a short tutorial on how it works.

It’s something we all use on our smartphones and tablets, pinch zoom. Using the multi-touch commands in AppGameKit to re-create a pinch zoom effect is not simple. It’s pretty easy to detect when you have two fingers on the screen and how far apart they are / were and adjust the view zoom accordingly but to get two finger scroll / pan and detecting taps on the screen at the same time can be a bit more complicated.

As I said we needed this for “Hide It Find It” so I simplified some existing code I had for pinch zoom into a few functions and some simple setup code. If you want to use the code in your game you can do so by:

1 – Initialising the command set:


2 – Setting up the min / max zoom variables:


3 – Then all you need to do is include the pinch zoom function in your loop when you want it possible to zoom. The setupPinchZoom function can be used to change the values allowed at any time.


There is a simple example project that you can compile and broadcast to your touch-screen device to try out attached but read on if you would like to learn a little more about how this works.

Edit: Fixed code to allow for image offset from 0,0. The example now shows the image squashed to half height as an example. Also I have improved the zoom out code to work better.


this.mess = abs(sin(times#))

Attachments

Login to view attachments
baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 22nd Apr 2013 14:13
Part 1
First we need to capture the multi-touch information from AppGameKit and turn it into something we can use. I started this process by making a UDT array to store the data for each touch event. My UDT looks like this:


I am also calling a single function from within my “pinchZoom()” function to fill in the data in this array. Here is (basically) what that function does.

First I reset some data that needs to be worked out in each loop as touch data changes constantly depending on what the user is doing:


Next I loop through all of the current touch events. I check the ID of the touch event to check if it is new or an event I am already aware of:


Then I check for any events that no longer exist and remove them from the array:


Finally I update some data to keep track of which is the first / second event, also I track when the last event took place so that the pinch zoom code can zoom out after 5 seconds of inactivity. Perhaps it would be sensible to move this code into the pinch zoom function but I am happy keeping it in this function for now:


As you can see I am ignoring anything more than two touch events. If you wanted to use the data for more it is still being stored. Keeping track of multi touch ID’s is vital when using multi touch to make sure we are looking at the same touch event as before. If we assume that because there was one touch event in the last loop and there is still only one touch event in this loop that they are the same event we might miss a crossover that produces unexpected results.

In Part 2 I will explain how I use this data to control the view offsets and zoom.


this.mess = abs(sin(times#))
baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 24th Apr 2013 12:56 Edited at: 24th Apr 2013 12:59
Part 2
I start the pinch zoom function off by getting some vital data for the system:


I get some basic timer data using a simple function. I only store three parameters “time.current” which gets the value of “timer()”, “time.frame” which gets a value from “getFrameTime()” (this saves making multiple calls to these functions) and finally “time.delta” which is a timer based movement parameter based on the current time frame and a target FPS rate set on startup.

Next I get the multi-touch data as shown in Part 1, then I run through three possible scenarios based on the current number of touches on the screen.

No Touches
When there are no touches on screen I check a timer that is reset when there are one or more touches. If the timer is done the view zooms out to full automatically. This could easily be disabled by removing this case from the select statement. First I reduce the zoom until it reaches the minimum zoom.


As you can see I am reducing the zoom back to the minimum zoom after a certain period of inactivity. Next I just need to check that the view does not go over the edge of the image / zoom boundaries:


As you can see the boundaries are based on the left, right, top and bottom specified in the setup code allowing for the width of the screen and the current zoom level (vz#).

Part 3 will cover the single touch drag code when only one touch is detected.


this.mess = abs(sin(times#))
baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 24th Apr 2013 13:05
Part 3
When dragging with one finger all I need to do is check how far the user has dragged in x and y then apply this difference to the current offset. So here is how I get the offsets (ox# and oy#):


Next I apply these offsets to the current view:


Then I use a similar method of ensuring the offsets are within the zoom boundaries as I used in Part 2. Finally I check for a screen tap event (which is also a single touch event). I only check if the user has just lifted their finger and that the finger moved less than 30 pixels from its start position:


In Part 4 I will cover the two finger pan and zoom code.


this.mess = abs(sin(times#))
baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 24th Apr 2013 13:39 Edited at: 24th Apr 2013 13:40
Part 4
Two finger pan/drag and zoom requires that I store some data from the start of the event to ensure I get a more accurate result. If I only make changes on a frame by frame basis I find the result is a slightly jumpy zoom. I am currently storing this data into my multi touch array in the code from Part 1 when a two touch event is first detected. I start by getting this data here:


Then I calculate the distance between the touch events at the start and in the current frame. It might be quicker to store the start values too but I am not too worried about the speed of one extra sqrt() command call at this stage:


Now I have these two values I can calculate the difference in zoom from the initial action to the current frame (this is effectively; startZoom x (currentDist / startDist)):


Finally I need to apply an offset based on the centre of the two touch events at the start and in the current frame:


The basic principle here is that the zoom is based on the distance between the two fingers and the pan / drag is based on the distance between the point in the middle of the two fingers.

Please let me know if you have any further questions on the code!
Steve


this.mess = abs(sin(times#))
Ian Rees
AGK Developer
11
Years of Service
User Offline
Joined: 3rd May 2012
Location: Wales, UK
Posted: 25th Apr 2013 19:29
Nice work Baxslash.

I don't have a need for it at the moment but there's a chance I may in future projects!

Thanks for sharing.

Marl
12
Years of Service
User Offline
Joined: 19th Nov 2011
Location: Bradford, UK
Posted: 26th Apr 2013 19:41
I'll have to give this a go and see how it compares to what I currently do.

It's the same principal, but I do the zoom and offset on the fly. I'd not noticed any jumping, but it's worth having a backup in case I start to.
Naphier
13
Years of Service
User Offline
Joined: 2nd Oct 2010
Location: St Petersburg, Florida
Posted: 26th Apr 2013 23:37
I'm sure I'll need this at some point. Thanks for helping out, bax!

www.NaplandGames.com
bitJericho
21
Years of Service
User Offline
Joined: 9th Oct 2002
Location: United States
Posted: 25th Jul 2013 20:08 Edited at: 25th Jul 2013 20:08
What terms (license or whatever) is this released under if any?

Visit my blog http://www.canales.me.
baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 25th Jul 2013 22:39
bitJericho, no license. Just use it, if you want to thank me stick my name in the credits if you feel like it


this.mess = abs(sin(times#))
bitJericho
21
Years of Service
User Offline
Joined: 9th Oct 2002
Location: United States
Posted: 27th Jul 2013 03:07
You're the best!

Visit my blog http://www.canales.me.
joachim
12
Years of Service
User Offline
Joined: 21st Feb 2012
Location: Vancouver Canada
Posted: 27th Jul 2013 03:59
What is "utilities.agc" ?

and when you zoom, does it zoom around the center point
between the two fingers ?

and are there jumps when i take one finger of ?
baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 27th Jul 2013 10:07
Quote: "What is "utilities.agc" ?"

It's in the download in the bottom right corner of the first post. An "agc" file is a source code file you include in your project.

Quote: "and when you zoom, does it zoom around the center point
between the two fingers ?"

Yes it does

Quote: "and are there jumps when i take one finger of ?"

No, I don't think so. Try broadcasting the project to a device and you'll see


this.mess = abs(sin(times#))
DVader
20
Years of Service
User Offline
Joined: 28th Jan 2004
Location:
Posted: 27th Jul 2013 14:49
I always find this sort of thing awkward, so if I need in future I know where to look! Nice tutorial!

joachim
12
Years of Service
User Offline
Joined: 21st Feb 2012
Location: Vancouver Canada
Posted: 27th Jul 2013 15:54
Thanks for the quick response !

Its the first time that I hear about an .agc file.

regards.
easter bunny
11
Years of Service
User Offline
Joined: 20th Nov 2012
Playing: Dota 2
Posted: 31st Jul 2013 08:14 Edited at: 31st Jul 2013 08:16
A huge thanks for this!


Quote: "Its the first time that I hear about an .agc file."

they're very useful
[attached an image of my project Neon Bunniez, with 7000 lines of code, you need multiple files, 25 of them in this case]



Attachments

Login to view attachments
easter bunny
11
Years of Service
User Offline
Joined: 20th Nov 2012
Playing: Dota 2
Posted: 31st Jul 2013 08:22
any chance of a percentage based version?

baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 31st Jul 2013 10:25
Perhaps, but I don't have time right now... maybe later next week if that's any use.


this.mess = abs(sin(times#))
lilpissywilly
AGK Developer
13
Years of Service
User Offline
Joined: 10th Sep 2010
Location: Office Chair
Posted: 31st Jul 2013 11:38
This is brilliant baxslash.

As a sidenote that I didn't feel warranted its own thread; I just kind of realized that virtual buttons are multi-touch enabled. You can register hits on more than one virtual button at a time. Neat

My hovercraft is full of eels

Login to post a reply

Server time is: 2024-03-29 15:42:40
Your offset time is: 2024-03-29 15:42:40