We throw the puck in iOS eight

    Before creating a casual game for iOS, it would be nice to answer the question: - Why?
    Three options:
    • Cut money;
    • To please relatives;
    • Fuck knows, but thought burns the body from the inside.


    image

    I think in the coming years, the correct answer is the third.
    And, I will not argue and teach - I will tell you how I make applications.
    The development guru silently clicks the plus and walk away. The rest follow me to remember school and table hockey.
    And yes, the uniqueness of the topic is that in each sentence the words begin with different letters.
    The article has nine pictures and half a minute of funny animation.

    1. The idea


    The choice of tools depends on it. My ideas as smartphone users are straightforward. Because - no extra tools for development, except for the library of sound reproduction. I borrow resources from the network. Ringtones, design, images, code examples. Everything has already been created before us. Copyright - like in hockey or football. Let's say Messi invented a new feint. You can copy it without transferring money to the author.
    Okay. As an example of the game, I chose table hockey.
    Very personal
    The 80s. On the fur mat, this fun was popular. We played in the washroom FDS-6. I brag about the stellar moment - the crowd of people competed in the night. I went in, waited for the line, defeated the local champion 10-0 and modestly left. To be honest, I have two brothers and sixteen years of gambling practice.


    2. Start of the project


    image
    Figure 2. In Xcode, I’m looking for a new project.

    By the way, I have fat fingers. So, only the iPad mode is suitable for the game. This greatly facilitates the work. In addition, I prohibit screen rotation, allowing only portrait orientation. Long live the portrait, here you have hockey, not ballet.
    With the choice of the name of the application there is no difficulty - Hockey 2015 . Names of sports are profitable. As for the money, I, of course, misled. I would like the future opus to bring satisfaction, both spiritual and material. I already wrote here about my game Biathlon 2014. Every year - almost a thousand bucks. Buy during the World Cup, the Olympics, the cup stages. Who! Norwegians, Germans, Czechs, French, Russians, Italians.
    I think my future hockey is waiting for something similar just because of the name.

    I choose the icon. Not as important as the name. The main thing is to enjoy it yourself.
    image
    Figure 3. Whoever guesses what kind of hockey player he is, the prize is 1 dollar.

    As a result, we get a blank for a future game that displays a bright gray screen. The project has two main files that I can edit.
    • ViewController.xib
    • ViewController.m

    And I won’t, bad tone. Good tone is not too lazy and create another class of the ViewController type. For example, named PlayViewController.

    image
    Figure 4. Add a new PlayViewController.

    The project has two new files that I can always edit.
    • PlayViewController.xib
    • PlayViewController.m


    3. Still images


    I place the still images using the editor in the file PlayViewController.xib.
    First, you need to create, steal or borrow the pictures. Milfgard made images of the ice field, hockey players, and goalkeepers . In Mosigre there are. For which I without asking placed the Mosigra name label in the center of the field. The puck is from the net. Photos of the faces of hockey players - nhl.com. Buttons - from the designers of Zeptolab. Hockey sounds - from the Ice Rage app.
    Now you can place the images in the xib file editor. It's simple - all pictures are displayed by the UIImageView element.

    image
    Figure 5. Hockey field and scoreboard in the Xcode editor.

    If in the future you need animation of statically defined elements - it does not matter. I give the element a name. Now it can be programmed to move, extinguish, rotate, mock as you like.

    Example, declare the scoreBoard element (black scoreboard in the picture) in the file PlayViewController.m
       IBOutlet UIImageView *scoreBoard;
    

    The IBOutlet keyword means that in the XIB editor you can assign a scoreBoard identifier to any item.
    I assign a mouse in the editor.

    Now I can move the picture deep up so that it does not block the hockey field.
      scoreBoard.center = CGPointMake(384, -1000);
    

    I remind you, 384 is the center of the iPad screen in width, -1000 is something outside the device. After the command is executed, the scoreboard will fly up beyond the boundaries of the screen.

    If you want to move a group of pictures - they must be combined. Get an element of type UIView to move a group of pictures and labels into it.
    image
    Figure 6. So, unnecessary elements are removed from the ice.

    Now we’ll place the hockey players here to teach them how to move.


    4. Transformable images


    We place one hockey player programmatically in the file PlayViewController.m
       UIImageView *player =  [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"player_1.png"]];
        float rPlayer = 150.0;
       player.frame = CGRectMake(0, 0, rPlayer, rPlayer);
        player.center = CGPointMake(100, 500);
        [self.view addSubview:player];
     


    image
    Figure 7. A hockey player appeared on the court.

    In the future, I will move and rotate it. Like this.
        player.center = CGPointMake(xnew, ynew); // перемещаю в точку (xnew=100, ynew=440)
        player.transform = CGAffineTransformMakeRotation(alpha); // кручу хоккеиста на угол (alpha=2.0) в радианах
     


    image
    Figure 8. The hockey player left for another place and turned around.

    There are many hockey players, but I am alone. We place all 12 players using an array.
        NSMutableArray *players;
        players = [[NSMutableArray alloc] init];
        shadows = [[NSMutableArray alloc] init];
        for (int k=0; k<12; k++) {
            UIImageView *p =  [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"player_1"]];
            p.frame = CGRectMake(0, 0, cellDx, cellDx);
            float x = xp[k];
            float y = yp[k];
            p.center = CGPointMake(x, y);
            p.transform = CGAffineTransformMakeRotation(ap[k]);
            [players addObject:p];
            p = [players objectAtIndex:k];   // так можем получить доступ к любому из 12 хоккеистов
            [self.view addSubview:p];
        }
      


    5. Numerical methods in hockey


    Hockey, like life, depends on time.
    It is necessary to have a time counter. The event that the program will trigger 3,000 times per minute.

         NSTimer *pauseTimer;
        time = 0;
        deltaTime = 1.0/50.0;
        pauseTimer = [NSTimer scheduledTimerWithTimeInterval:deltaTime  target:self selector:@selector(timerFunction) userInfo:nil repeats:YES];
    - (void) timerFunction
    {
    // мы здесь бываем 50 раз в секунду
        time = time + deltaTime;
        [self renderPuck];
        [self renderPlayers];
        [self puckMoving:deltaTime];
    }
        


    So, all that remains for me is to paint the puckMoving function. In it I will check the collision of the puck and hockey players. Mathematically, the puck is defined by a circle with a radius of 21 pixels. Each hockey player has two circles - a larger (radius of 25 pixels) body. Smaller (5 pixel radius) - a club.

    Feature below, comments inside.
    puckMoving
           for (int k=1; k<33; k++) {
                    if ( [self checkCollision:i With:k] ) {
                        [self resolve:i With:k];
                    }
            }
    -(int) checkCollision:(int) k1 With:(int) k2
    {
        float d2 = [self distance2:k1 With:k2];
        float dr = rp2[k1] + rp2[k2];
        return ( d2 < dr*dr ? 1 : 0);
    }
    -(float) distance2:(int) k1 With:(int) k2
    {
        float dxx = xp2[k1] - xp2[k2];
        float dyy = yp2[k1] - yp2[k2];
        return dxx*dxx + dyy*dyy;
    }
    -(void) resolve:(int) k1 With:(int) k2
    {
        float x1 = xp2[k1];
        float y1 = yp2[k1];
        float x2 = xp2[k2];
        float y2 = yp2[k2];
        float u2 = up2[k2];
        float v2 = vp2[k2];
        float u1 = up2[k1];
        float v1 = vp2[k1];
        Vector *b1Velocity = [Vector alloc];
        [b1Velocity  initX:u1 initY:v1];
        Vector *b2Velocity = [Vector alloc];
        [b2Velocity  initX:u2 initY:v2 ];
        float b1Mass   = mp2[k1];
        float b2Mass   = mp2[k2];
        Vector *vv = [Vector alloc];
        [vv  initX:x1-x2 initY:y1-y2];
        float distance = [vv magnitude];
        float min_distance = rp2[k1] + rp2[k2];
        if (distance < min_distance) {
            [vv mulScalar: ((0.1+min_distance-distance)/(distance)) ];
            x1 += vv.x;
            y1 += vv.y;
            xp2[k1] = x1;
            yp2[k1] = y1;
        }
        Vector *lineOfSight = [Vector alloc];
        [lineOfSight initX:x1-x2 initY:y1-y2];
        Vector *v1Prime = [b1Velocity vectorProjectionOnto:lineOfSight];
        Vector *v2Prime = [b2Velocity vectorProjectionOnto:lineOfSight];
        Vector *v1Prime2 = [Vector alloc];
        [v1Prime2 copyVector:v2Prime];
        [v1Prime2 mulScalar:(2*b2Mass)];
        [v1Prime2 addVector:[v1Prime getMulScalar:(b1Mass - b2Mass)] ];
        [v1Prime2 mulScalar:(1.0/(b1Mass + b2Mass))];
        Vector *v2Prime2 = [Vector alloc];
        [v2Prime2 copyVector:v1Prime];
        [v2Prime2 mulScalar:(2*b1Mass)];
        [v2Prime2 subVector: [v2Prime getMulScalar:(b1Mass - b2Mass)] ];
        [v2Prime2 mulScalar:(1.0/(b1Mass + b2Mass))];
        [v1Prime2 subVector:(v1Prime)];
        [v2Prime2 subVector:(v2Prime)];
        [b1Velocity addVector:v1Prime2];
        [b2Velocity addVector:v2Prime2];
        float a = 0.999;
        up2[k1] = a*b1Velocity.x + (1.0-a)*b2Velocity.x;
        vp2[k1] = a*b1Velocity.y + (1.0-a)*b2Velocity.y;
        a = 1.0 - a;
        //    NSLog(@"new speed %f", hypotf(u, v)) );
    }
     


    Inside the function, the Vector class is used.
    class Vector
    #import "Vector.h"
    @implementation Vector
    @synthesize x,y;
    -(void) initX:(float) setX  initY:(float) setY  {
    	x = setX;
    	y = setY;
    }
    -(void) copyVector:(Vector*) v{
    	x = v.x;
    	y = v.y;
    }
    -(void) addVector:(Vector*) v {
    	x += v.x;
    	y += v.y;
    }
    -(void) subVector:(Vector*) v {
    	x -= v.x;
    	y -= v.y;
    }
    -(void) mulScalar:(float) f {
    	x *= f;
    	y *= f;
    }
    -(float) magnitude {
    	return sqrt( x*x + y*y );
    }
    -(float) magnitude2 {
    	return  x*x + y*y;
    }
    -(Vector *)getMulScalar:(float) f {
    	Vector *v = [Vector alloc];
    	[v initX:x*f initY:y*f];
    	return v;
    }
    -(float) scalarProjectionOnto:(Vector*) v {
    	return (x* v.x + y*v.y)/ [v magnitude];
    }
    -(Vector *) vectorProjectionOnto:(Vector*) v {
    	Vector *res = [v getUnitVector];
    	[res mulScalar: [self scalarProjectionOnto:v]];
    	return res;
    }
    -(Vector *) getUnitVector {
    		float len = [ self magnitude];
    		Vector *res = [Vector alloc];
    		[res initX:x initY:y];
    		if (len>0) {
    			len = 1.0/len;
    			[res mulScalar:len];
    		}
    		return res;
    	}
    @end
    



    When numerically modeling the movement of the puck, there is one trick. 50 times per second is not enough for simulation accuracy. I use an elementary trick - I’ll double the number of calls to puckMoving, breaking the time step into ten accordingly.

    - (void) timerFunction
    {
    // мы здесь бываем 50 раз в секунду
        time = time + deltaTime;
        [self renderPuck];
        [self renderPlayers];
        for (int k=0; k<10; k++)  [self puckMoving:deltaTime/10.0];
    }
        


    We look what happened



    6. Statistics know everything


    Russians and Americans love statistics. Therefore, I organized a tournament of the six best teams in the world.
    Real players from nhl.com, goals, goals, points, all stars of the tournament.

    7. Testing


    Apple allows 1,000 testers at the app revision stage.

    Don't come in, advertisement
    At night, the application was approved in the Apple store. A week the game will be paid, then I will talk about the number of downloads.


    Thank you for reading.

    Also popular now: