📜 ⬆️ ⬇️

We program under Pebble. Lesson two: Pebble giving answers, dice and sex cubes

The clock is nice, but the whole site is full of them. We need to do something more interesting.
image
Remember the ball from “highway 60”? Let's make it an analogue - an application that answers the question.


Ball Pebble giving answers

Only we will have not a ball, but a pebble, that is, a Pebble :)
What do we need for this? List of answers and random number generator. We will take the list of answers on Wikipedia . Create an array and fill it with answers:
static const char* messages[] = {"", " "," "," ","    ","  - "," "," ","","  - ","  ,   "," ","     ","  ","   ","  ","  - ","  - ","   "," ","",}; 
The order is not important, they will still be chosen randomly from it.

We create the main window of the program and the text layer in the same way as in the previous lesson , with the exception of a small difference - using the window_set_fullscreen () function, we remove the top bar of the application. It is called like this:
  window_set_fullscreen(window, true); 
The first argument is the name of the window, the second, respectively, true - full screen, false - with bar. Subtlety - this function must be called before window_stack_push, otherwise the miracle will not happen.
')
Now let's do a random number generator. To do this, there is a rand () function that returns a random number with each call. Like any RNG software, it needs to be initialized with a random number before starting work, otherwise the line of numbers will be repeated each time it is started. This is done by the srand () function. For example, in the SDK there is an example where it is initialized by the current time. Since we do not know at what time the program will start, and this time is different every time - this is a sufficient source of entropy for our idea. Do this like this:
 srand(time(NULL)); 

True, the generator can now produce a fairly large number - obviously more than we have possible answers. Therefore, using the following messages [rand ()% 21] construct. % Is the remainder of an integer division. Suppose the generator returns 456, they are divided by 21, and we use the remainder (456-21 * 21) - 15 as the answer number. It can not be more than 21, because the remainder of the division will be equal to zero.

We merge all of the above into one, and we get this function call:
 text_layer_set_text(text_layer, messages[rand() % 21]); 

Here is the whole source:
 #include "pebble.h" Window *window; /*     */ TextLayer *text_layer; /*      */ static const char* messages[] = {"", " "," "," ","    ","  - "," "," ","","  - ","  ,   "," ","     ","  ","   ","  ","  - ","  - ","   "," ","",}; /*    */ int main(void) { window = window_create(); /*   */ window_set_background_color(window, GColorBlack); /*    */ window_set_fullscreen(window, true); /*   */ window_stack_push(window, true); /*   */ text_layer = text_layer_create(GRect(1, 47, 142, 77)); /*    */ text_layer_set_text_color(text_layer, GColorWhite); /*    */ text_layer_set_background_color(text_layer, GColorClear); /*    */ text_layer_set_font(text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24)); /*   */ text_layer_set_text_alignment(text_layer, GTextAlignmentCenter); /*     */ layer_add_child(window_get_root_layer(window), text_layer_get_layer(text_layer)); /*         */ srand(time(NULL)); /*       */ text_layer_set_text(text_layer, messages[rand() % 21]); /*        */ app_event_loop(); /*  - */ text_layer_destroy(text_layer); /*  ,   */ window_destroy(window); /*  ,   */ } 

The program displays a message at startup and no longer does anything. To show another message, restart the program:


The next step is to display the message when you click on the button.

In the Pebble API, the term “subscription” is used to assign functions that will be launched not in the main loop, but after some actions - a timer tick, a button click, and so on. Remember, in the last lesson, we subscribed to a timer that called the screen refresh function once a second? There is something similar, we subscribe to a button click (and the API already has several ready-made options - a single click , double click , hold, and so on), after which we click the function we set will be started.

The API says that we need to call the window_set_click_config_provider () method, which takes as arguments the pointer to the window in which to click, and the name of the function that describes the subscriptions. Please note, we will not subscribe to the buttons, but only in the function specified in window_set_click_config_provider . This is done like this:
 window_set_click_config_provider(window, WindowsClickConfigProvider); 
The window pointer is window, the function name is WindowsClickConfigProvider. Create it:
 void WindowsClickConfigProvider(void *context) { } 

And we add inside the window_single_click_subscribe methods that take the name of the button and the function to which the control will be passed as arguments:
 window_single_click_subscribe(BUTTON_ID_UP, click); 
In this case, when you press the up button, we call click.
The buttons (we have 3 of them) are called BUTTON_ID_UP, BUTTON_ID_SELECT, BUTTON_ID_DOWN, respectively. You can subscribe to the "back" button, but it will always throw you out to the previous screen (in case the application has one screen - in the menu).

Now the application looks like this:


And its source:
 #include "pebble.h" Window *window; /*     */ TextLayer *text_layer; /*      */ static const char* messages[] = {"", " "," "," - ","   ","  - "," "," ","","  - ","  ,   "," ","     ","  ","   ","  ","  - ","  - ","   "," ","",}; /*    */ void click(ClickRecognizerRef recognizer, void *context) /*        */ { text_layer_set_text(text_layer, messages[rand() % 21]); /*        */ } void WindowsClickConfigProvider(void *context) /* ,        */ { window_single_click_subscribe(BUTTON_ID_UP, click); /*       click */ window_single_click_subscribe(BUTTON_ID_SELECT, click); window_single_click_subscribe(BUTTON_ID_DOWN, click); } int main(void) { window = window_create(); /*   */ window_set_background_color(window, GColorBlack); /*    */ window_set_fullscreen(window, true); /*   */ window_stack_push(window, true); /*   */ text_layer = text_layer_create(GRect(0, 7, 144, 168)); /*    */ text_layer_set_text_color(text_layer, GColorWhite); /*    */ text_layer_set_background_color(text_layer, GColorClear); /*    */ text_layer_set_font(text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24)); /*   */ text_layer_set_text_alignment(text_layer, GTextAlignmentCenter); /*     */ layer_add_child(window_get_root_layer(window), text_layer_get_layer(text_layer)); /*         */ srand(time(NULL)); /*       */ window_set_click_config_provider(window, WindowsClickConfigProvider); /*  ,        */ text_layer_set_text(text_layer, "Magic Pebble \n  ,     \"\"  \"\"    "); /*     */ app_event_loop(); /*   */ text_layer_destroy(text_layer); /*  ,   */ window_destroy(window); /*  ,   */ } 



Works! You can assign version 0.1 :)
But something is missing. It would be nice to add some effects. You can make an animation of changing the responses so that the clock responds not immediately when you press the button, but for a few seconds “sorted out” options. In quotes - because the answer will be random in any case, but in the first case the user will have more confidence in the application - we are all familiar with the random process of choosing cards from the bag or balls with numbers when playing the lottery.

It will be even more beautiful if we add a little physics. The fact is that people, without knowing it, are surrounded by processes proceeding along the reciprocal exponential - when the processes are “fast” at the very beginning, they do not pass linearly, but they lose speed the more, the more time has passed since the beginning.
It could be anything - for example, cooling hot tea on the table. When the temperature difference between tea and ambient air is great, it cools much faster than when it is slightly warm. Or bubbles in a glass of carbonated water. At first, when the concentration of carbonic acid in water is high, it decomposes very actively, but after a while the concentration decreases, and with it the number of bubbles decreases.
In this case, I would like to do something like a wheel of fortune - where the segments first replace each other quickly, slowly slowing down. Here the friction is “guilty” - the more speed, the more the wheel rubs against the axis and the more it loses energy, transferring it to heat and slowing down. But with decreasing speed losses and friction are reduced - as a result, the wheel loses 50% of its speed in the first 20% of the time, and the remaining 50% in the remaining 70%.

We will count time in milliseconds between shifts of messages. By experiments, it was found that a good range of values ​​- from 0 to 300-400ms. If the intervals are longer, there is a feeling that the already shown answer has suddenly changed.
The simplest function that provides this behavior is something like x = x * 2. But when multiplied by 2, the graph of the function rises too abruptly, with each iteration the delay time doubles. We will get 256 (the maximum delay, since the next value - 512 already goes beyond the limits of convenience) already at step 8 with a duration of only 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 + 256 = 511ms. Half a second is too fast.
By experience, I realized that the multiplier should be around 1.08-1.2, then we get about 30 steps and a duration of about 3 seconds. But I do not like the function x = x * y - it rises too hollow, and the flickering slows down too slowly (yes, I'm strange), I would like it to flash “quickly” longer, and then abruptly stop.

It could have been easier to do - to score the value of the delays in the array and rub them in, edit them, edit them until satisfaction, since there are not so many of them - 40 pieces. Once multiplication does not suit us, try division. Something like x = x / 0.7. But by itself, it increases too sharply - 300 we get at the 18th step, and I would like a little more. But it can be divided, for example, by 100. Or by 1000. Let's build graphs of all functions with an initial value of 1. The numbers above the graphs are the number of steps.

Here, it means that y = y / 0.7 x = y / 100 is quite suitable for us, we can do.

But first, let's fix one glitch: information at startup and messages are displayed in the same layer, then messages are displayed at the top of the screen (unfortunately, there is no vertical alignment). Yes, and small print, although they can be done and more - they are much shorter and fit in the screen. I did not find a layer resizing method in the API, so we will have to delete the layer and create it again, but with different coordinates. However, this will turn out ugly - a part of the code will be duplicated (layer settings after its creation) to prevent this from happening - we will move part of the code into a separate function.
Create:
 void config_text_layer(int16_t x,int16_t y,int16_t h,int16_t w, const char *font_key) { } 

The first 4 parameters are the information about the layer — the coordinates of the point and the dimensions; the fifth parameter is the font. Accordingly, we rewrite the initialization functions to use these variables:
 text_layer = text_layer_create(GRect(x, y, h, w)); text_layer_set_font(text_layer, fonts_get_system_font(font_key)); 

And paste them into our function along with the rest of the layer setup code. Now you can just do it in the right place like this:
 text_layer_destroy(text_layer); config_text_layer(5, 40, 134, 120, FONT_KEY_GOTHIC_28); 

So let's do it in the click function, which is called by us when the button is pressed. Yes, a layer will be created every time a button is pressed; this can be avoided by simply checking something like:
 bool first_time=true; if (first_time == true) { text_layer_destroy(text_layer); config_text_layer(5, 40, 134, 120, FONT_KEY_GOTHIC_28); first_time = false; } 

But I did not bother. Better deal with the timer. An API search gave the app_timer_register () function, which takes as arguments the value in ms, through which the timer will work, the name of the function to be called when it is triggered, and a pointer to the data to be passed to this function. Unfortunately, I didn’t figure out how to work with the pointer, so I’ll have to spit on the beauty of the code and do it through a global variable:
 float timer_delay=1; 


We create a function that will recursively call a timer at ever-increasing intervals.

 void timer_call() /*       */ { text_layer_set_text(text_layer, messages[rand() % 21]); /*    */ if (timer_delay < 300*100 ) /*      300... */ { timer_delay=timer_delay/0.7; /* ... ... */ app_timer_register(timer_delay/100, timer_call, NULL); /* ...    */ } else /*     300... */ { timer_delay=1; /*       -     */ } } 

The center of the function is the variable floating point timer_delay. It is divided by 0.7 until it reaches 30000. Each new value of the variable is divided by 100 and given as an argument to the delay of the app_timer_register function, which, when triggered, will call this function again.

It remains only to add a call to this function in click () :
 void click(ClickRecognizerRef recognizer, void *context) /* ,      */ { text_layer_destroy(text_layer); /*      */ config_text_layer(5, 40, 134, 120, FONT_KEY_GOTHIC_28); /*         */ timer_call(); /*       */ } 

And you can enjoy the result:

If we think a bit about what we did, then it turns out that we have created a platform for simulating any pieces that are used in the real world as RNG. The complex movement of a multifaceted figure in the fluid inside the ball is a process that cannot be predicted. Just like the dice. By the way, dice! What is not an option for another application?
I really wanted to look for pictures on the edges of the bones and came across ... no, well, these are also drawings. And also on the dice. Just dots. In general, I stumbled upon this:


And that's all. What are there dice when there is such a great idea? Come sell!

Sex Roulette

The logic of the program remains the same. Change the messages array:
 static const char* messages[] = {" "," "," "," "," "," "," "," "," "," "," "," "," "," ","  "," "," "," ","  "," "," "," ","  ",}; 

And a message at startup:
 text_layer_set_text(text_layer, "Sex Roulette \n    ,      -->"); 

We create in memory to which the pointer points a graphic array, indicating coordinates. The syntax is exactly the same as in text_layer_create:
 image_layer = bitmap_layer_create(GRect(0 , 0, 144, 144)); 

Make the layer created by the child of the main window layer. Why do you need it? This adjusts the “height” (in terms of css, if it is clearer to whom it is the z-index) of a layer with respect to other layers, it depends on how the layers overlap each other. All children are above the parent and close it with their conclusion.
 layer_add_child(window_get_root_layer(window), bitmap_layer_get_layer(image_layer)); 

Customize blending mode. Depending on this parameter, the picture will interact in different ways with the background.
 bitmap_layer_set_compositing_mode(image_layer, GCompOpAssignInverted); 

All options can be described here , or you can poke in the picture:
image
Source is in this case the graphics layer, and Destination is its parent, the main layer of the window. As everything is simply and remarkably fit into 6 options when working with monochrome pictures ...

Now we will deal with the display of random pictures. We will look for suitable pictures in Google (two-color and small) for some kind of " icon poses ".
This site found this:

We download the vector, delete any borders, export it to PNG with a higher resolution, open it in some graphic editor.
Select each picture, delete the unsuccessful and incomprehensible, fit it into a square, reduce it to 144 pixels, clean up the flaws. The result of our work should be a folder with pictures:

From one of the pictures we make a logo for the menu, 24x28 pixels in size:
->

Open the appinfo.json file in the project folder and add our created resources to it. Unfortunately, I can’t tell you how this is done in CloudPebble - it suddenly stopped working for me, not accepting the password and holding the sources of all my projects. So I set up the development environment for myself on the computer according to the instructions from the official site, and write there.

So, about appinfo.json. It looks like this:
 { "uuid": "0f7b8336-d72d-4806-9191-566ffd8f3a8c", "shortName": "SexRoulette", "longName": "SexRoulette", "companyName": "vvzvlad", "versionCode": 1, "versionLabel": "1.0.0", "watchapp": { "watchface": false }, "appKeys": { "dummy": 0 }, "resources": { "media": [ { "menuIcon": true, "type": "png", "name": "DEFAULT_MENU_ICON", "file": "img/logo.png" }, { "type": "png", "name": "POSE_1", "file": "img/1.png" }, 
At the beginning are familiar fields, the meaning of which is clear and without explanation, and then it describes all 32 pictures. Please note that the structure should be exactly like this:

  { "type": "png", "name": " ", "file": "img/1.png" }, { "type": "png", "name": " ", "file": "img/1.png" } 

After the last bracket should not be a comma, as well as after specifying the file address. And the fields should follow exactly in the order type, name, file.
What the hell goes against the official documentation :

Keyboard in the ass cram! I send rays of diarrhea to those who wrote this documentation, I was stupid for half an hour and wondered what he was cursing. He even swears so indistinctly that one really does not understand what does not suit him:
 Traceback (most recent call last): File "/Users/vvzvlad/Documents/PebbleSDK-2.0-BETA2/Pebble/.waf-1.7.11-478a7e7e9ed077304a8092741524bf8b/waflib/Scripting.py", line 351, in execute return execute_method(self) File "/Users/vvzvlad/Documents/PebbleSDK-2.0-BETA2/Pebble/.waf-1.7.11-478a7e7e9ed077304a8092741524bf8b/waflib/Build.py", line 106, in execute self.execute_build() File "/Users/vvzvlad/Documents/PebbleSDK-2.0-BETA2/Pebble/.waf-1.7.11-478a7e7e9ed077304a8092741524bf8b/waflib/Build.py", line 109, in execute_build self.recurse([self.run_dir]) File "/Users/vvzvlad/Documents/PebbleSDK-2.0-BETA2/Pebble/.waf-1.7.11-478a7e7e9ed077304a8092741524bf8b/waflib/Context.py", line 128, in recurse user_function(self) File "/Users/vvzvlad/Documents/PebbleSDK-2.0-BETA2/SexRoulette/wscript", line 18, in build ctx.load('pebble_sdk') 
Well, to hell with him. As you already understood, the icon picture for the menu is marked with the “menuIcon” field : true , and you can also access it from the program.

Let's return to our pictures. Documentation suggests uploading a picture like this:
 image = gbitmap_create_with_resource(RESOURCE_ID_POSE_1); 

What is not suitable for us. Do not fence the same type of monstrous design
 select rand() % 31 case 1 image = gbitmap_create_with_resource(RESOURCE_ID_POSE_1); case 2 image = gbitmap_create_with_resource(RESOURCE_ID_POSE_2); 

It's not beautiful. From the documentation, we understand that RESOURCE_ID_POSE_2 is just a variable of type uint32_t in which the resource number is stored.

Create an array of the type we need:
 static const uint32_t images[] 

And we list in it the resources we need:
 static const uint32_t images[] = {RESOURCE_ID_POSE_1,RESOURCE_ID_POSE_2,RESOURCE_ID_POSE_3,RESOURCE_ID_POSE_4,RESOURCE_ID_POSE_5,RESOURCE_ID_POSE_6,RESOURCE_ID_POSE_7,RESOURCE_ID_POSE_8,RESOURCE_ID_POSE_9,RESOURCE_ID_POSE_10,RESOURCE_ID_POSE_11,RESOURCE_ID_POSE_12,RESOURCE_ID_POSE_13,RESOURCE_ID_POSE_14,RESOURCE_ID_POSE_15,RESOURCE_ID_POSE_16,RESOURCE_ID_POSE_17,RESOURCE_ID_POSE_18,RESOURCE_ID_POSE_19,RESOURCE_ID_POSE_20,RESOURCE_ID_POSE_21,RESOURCE_ID_POSE_22,RESOURCE_ID_POSE_23,RESOURCE_ID_POSE_24,RESOURCE_ID_POSE_25,RESOURCE_ID_POSE_26,RESOURCE_ID_POSE_27,RESOURCE_ID_POSE_28,RESOURCE_ID_POSE_29,RESOURCE_ID_POSE_30,RESOURCE_ID_POSE_31,RESOURCE_ID_POSE_32,}; 

Now we can call a random image in the same way as the text:
 image = gbitmap_create_with_resource(images[rand() % 31]); 

We called a picture from nonexistence from flash memory and placed it in the RAM. bitmap_layer_set_bitmap, .
:
 bitmap_layer_set_bitmap(image_layer, image); 

image_layer — , image — .
Look like that's it. Run!

, , Recovery .
, , , . , - , , .
spaaarta! embeeeeedded! .
. , .
 gbitmap_destroy(image); image = gbitmap_create_with_resource(images[rand() % 31]); bitmap_layer_set_bitmap(image_layer, image); 

image , gbitmap_destroy . App Crashed…
, , - . , - . :
 bool first_time=true; 

, :
 void timer_call() { first_time = false; 


gbitmap_destroy — first_time == false, text_layer_destroy config_text_layer click — , first_time == true:
 void timer_call() { if (first_time == false) { gbitmap_destroy(image); bitmap_layer_destroy(image_layer); } first_time = false; ..... void click(ClickRecognizerRef recognizer, void *context) { if (first_time == true) { text_layer_destroy(text_layer); config_text_layer(0, 146, 144, 168-146, FONT_KEY_GOTHIC_18); } 

Works!


, . :
  text_layer_destroy(text_layer); window_destroy(window); gbitmap_destroy(image); bitmap_layer_destroy(image_layer); 

gbitmap. , ! , — . . — , :
 if (first_time == false) { gbitmap_destroy(image); } 

.
 #include "pebble.h" float timer_delay=1; /*        */ Window *window; /*     */ TextLayer *text_layer; /*      */ static BitmapLayer *image_layer; /*      */ static GBitmap *image; /*       */ bool first_time=true; /*     */ static const char* messages[] = {" "," "," "," "," "," "," "," "," "," "," "," "," "," ","  "," "," "," ","  "," "," "," ","  ",}; /*    */ static const uint32_t images[] = {RESOURCE_ID_POSE_1,RESOURCE_ID_POSE_2,RESOURCE_ID_POSE_3,RESOURCE_ID_POSE_4,RESOURCE_ID_POSE_5,RESOURCE_ID_POSE_6,RESOURCE_ID_POSE_7,RESOURCE_ID_POSE_8,RESOURCE_ID_POSE_9,RESOURCE_ID_POSE_10,RESOURCE_ID_POSE_11,RESOURCE_ID_POSE_12,RESOURCE_ID_POSE_13,RESOURCE_ID_POSE_14,RESOURCE_ID_POSE_15,RESOURCE_ID_POSE_16,RESOURCE_ID_POSE_17,RESOURCE_ID_POSE_18,RESOURCE_ID_POSE_19,RESOURCE_ID_POSE_20,RESOURCE_ID_POSE_21,RESOURCE_ID_POSE_22,RESOURCE_ID_POSE_23,RESOURCE_ID_POSE_24,RESOURCE_ID_POSE_25,RESOURCE_ID_POSE_26,RESOURCE_ID_POSE_27,RESOURCE_ID_POSE_28,RESOURCE_ID_POSE_29,RESOURCE_ID_POSE_30,RESOURCE_ID_POSE_31,RESOURCE_ID_POSE_32,}; /*     */ void timer_call() /*       */ { if (first_time == false) /*      ... */ { bitmap_layer_destroy(image_layer); /* ...   ... */ gbitmap_destroy(image); /* ..      */ } first_time = false; /*     */ image = gbitmap_create_with_resource(images[rand() % 31]); /*         */ bitmap_layer_set_bitmap(image_layer, image); /*      */ text_layer_set_text(text_layer, messages[rand() % 23]); /*    */ if (timer_delay < 300*100 ) /*      300... */ { timer_delay=timer_delay/0.7; /* ... ... */ app_timer_register(timer_delay/100, timer_call, NULL); /* ...    */ } else /*     300... */ { timer_delay=1; /*       -        */ } } void config_text_layer(int16_t x,int16_t y,int16_t h,int16_t w, const char *font_key) /*    ,  ,       */ { text_layer = text_layer_create(GRect(x, y, h, w)); /*   ,     */ text_layer_set_text_color(text_layer, GColorWhite); /*    */ text_layer_set_background_color(text_layer, GColorClear); /*    */ text_layer_set_font(text_layer, fonts_get_system_font(font_key)); /*   */ text_layer_set_text_alignment(text_layer, GTextAlignmentCenter); /*     */ layer_add_child(window_get_root_layer(window), text_layer_get_layer(text_layer)); /*         */ } void click(ClickRecognizerRef recognizer, void *context) /* ,      */ { if (first_time == true) /*      ... */ { text_layer_destroy(text_layer); /* ...     ... */ config_text_layer(0, 146, 144, 168-146, FONT_KEY_GOTHIC_18); /* ...           */ } timer_call(); /*       */ } void WindowsClickConfigProvider(void *context) /* ,        */ { window_single_click_subscribe(BUTTON_ID_UP, click); /*       click */ window_single_click_subscribe(BUTTON_ID_SELECT, click); window_single_click_subscribe(BUTTON_ID_DOWN, click); } int main(void) { window = window_create(); /*   */ window_set_background_color(window, GColorBlack); /*    */ window_set_fullscreen(window, true); /*    */ window_stack_push(window, true); /*   */ srand(time(NULL)); /*       */ window_set_click_config_provider(window, WindowsClickConfigProvider); /*  ,        */ config_text_layer(0, 20, 144, 168, FONT_KEY_GOTHIC_24); /*        */ text_layer_set_text(text_layer, "Sex Roulette \n    ,      -->"); /*     */ image_layer = bitmap_layer_create(GRect(0 , 0, 144, 144)); /*   ,     */ layer_add_child(window_get_root_layer(window), bitmap_layer_get_layer(image_layer)); /*         */ bitmap_layer_set_compositing_mode(image_layer, GCompOpAssignInverted); /*    */ app_event_loop(); /*   */ text_layer_destroy(text_layer); /*   ,   */ window_destroy(window); /*   ,   */ bitmap_layer_destroy(image_layer); /*   ,   */ if (first_time == false) /*      ... */ { gbitmap_destroy(image); /*     ,  ,  -  , ..     */ } } 
?! .


. . 7575 :

appinfo.json, , images:
 static const uint32_t images[] = {RESOURCE_ID_DICE_1,RESOURCE_ID_DICE_2,RESOURCE_ID_DICE_3,RESOURCE_ID_DICE_4,RESOURCE_ID_DICE_5,RESOURCE_ID_DICE_6,}; 

: WindowsClickConfigProvider click . , ! .

:
 accel_tap_service_subscribe(accel_int); 

, :
 void accel_int(AccelAxisType axis, int32_t direction) { if (first_time == true) { text_layer_destroy(text_layer); } timer_call(); } 

: ( ) — . — :) .

timer_call . ( , — 144144, ), . — . rand . 7575 144168. , , , 0...69(144-75) -, 0...93(168-75) y-. : rand()%(144-75) rand()%(168-75) . :
 image_layer = bitmap_layer_create(GRect(rand()%(144-75), rand()%(168-75), 75, 75)); 


:
 if (timer_delay < 300*1000 ) { timer_delay=timer_delay/0.7; app_timer_register(timer_delay/1000, timer_call, NULL); } 
100, — 1000. . , , . , — , , — , .

, . : , . . , API :
 light_enable(bool enable) light_enable_interaction() 

Not much. . : l ight_enable(true) light_enable(false) , — , ( ). ( , ?), . - timer_call .
main :
 text_layer_set_text(text_layer, "    "); 

:
 if (first_time == true) { text_layer_destroy(text_layer); } else { bitmap_layer_destroy(image_layer); gbitmap_destroy(image); } accel_tap_service_unsubscribe(); 
. — , . — , — , — accel_int

 #include "pebble.h" float timer_delay=1; /*        */ Window *window; /*     */ TextLayer *text_layer; /*      */ static BitmapLayer *image_layer; /*      */ static GBitmap *image; /*       */ bool first_time=true; /*     */ static const uint32_t images[] = {RESOURCE_ID_DICE_1,RESOURCE_ID_DICE_2,RESOURCE_ID_DICE_3,RESOURCE_ID_DICE_4,RESOURCE_ID_DICE_5,RESOURCE_ID_DICE_6,}; /*      */ void timer_call() /*            */ { if (first_time == false)/*      ... */ { bitmap_layer_destroy(image_layer); /* ...   ,     ... */ gbitmap_destroy(image); /* ...      */ } first_time = false; /*     */ image_layer = bitmap_layer_create(GRect(rand()%(144-75), rand()%(168-75), 75, 75)); /*     ,     */ layer_add_child(window_get_root_layer(window), bitmap_layer_get_layer(image_layer)); /*    */ image = gbitmap_create_with_resource(images[rand() % 6]); /*         */ bitmap_layer_set_bitmap(image_layer, image); /*      */ light_enable_interaction(); /*   */ if (timer_delay < 300*1000 ) /*      300... */ { timer_delay=timer_delay/0.7; /* ... ... */ app_timer_register(timer_delay/1000, timer_call, NULL); /* ...    */ } else /*     300... */ { timer_delay=1; /*       -        */ } } void accel_int(AccelAxisType axis, int32_t direction) /*     ... */ { if (first_time == true) /*    ... */ { text_layer_destroy(text_layer); /* ...      */ } timer_call(); /*   */ } int main(void) { window = window_create(); /*   */ window_set_background_color(window, GColorBlack); /*    */ window_set_fullscreen(window, true); /*   */ window_stack_push(window, true); /*     */ srand(time(NULL)); /*       */ text_layer = text_layer_create(GRect(0 , 30, 144, 168)); /*   ,     */ text_layer_set_text_color(text_layer, GColorWhite); /*    */ text_layer_set_background_color(text_layer, GColorClear); /*    */ text_layer_set_font(text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28)); /*   */ text_layer_set_text_alignment(text_layer, GTextAlignmentCenter); /*     */ layer_add_child(window_get_root_layer(window), text_layer_get_layer(text_layer)); /*         */ text_layer_set_text(text_layer, "    "); /*     */ accel_tap_service_subscribe(accel_int); /*      */ app_event_loop(); /*   */ if (first_time == true) /*     ... */ { text_layer_destroy(text_layer); /* ...      */ } else /*     ... */ { bitmap_layer_destroy(image_layer); /* ...   ... */ gbitmap_destroy(image); /* ...     ,       accel_int */ } accel_tap_service_unsubscribe(); /*     */ window_destroy(window); /*   ,   */ } 


Works!


, :


Links

image MagicPebble mypebblefaces.com
image - mypebblefaces.com
image mypebblefaces.com
image MagicPebble github.com
image - github.com
image github.com
image , Pebble , . ( « pebble »). , — .


Source: https://habr.com/ru/post/204514/


All Articles