1 /*
2  * Luola - 2D multiplayer cave-flying game
3  * Copyright (C) 2006 Calle Laakkonen
4  *
5  * File        : spring.c
6  * Description : Spring physics
7  * Author(s)   : Calle Laakkonen
8  *
9  * Luola is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Luola is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  */
23 
24 #include <stdlib.h>
25 #include <math.h>
26 
27 #include "defines.h" /* For Round() */
28 #include "console.h"
29 #include "spring.h"
30 
31 /* Create a new spring */
create_spring(struct Physics * head,float nodelen,int nodecount)32 struct Spring *create_spring(struct Physics *head,float nodelen, int nodecount)
33 {
34     struct Spring *spring = malloc(sizeof(struct Spring));
35     if(!spring) {
36         perror("create_spring");
37         return NULL;
38     }
39 
40     spring->head = head;
41     spring->tail = malloc(sizeof(struct Physics));
42     init_physobj(spring->tail,head->x,head->y,makeVector(0,0));
43 
44     spring->sc = -0.6;
45     spring->color = col_rope;
46 
47     spring->nodelen = nodelen;
48     spring->nodecount = nodecount;
49     if(nodecount) {
50         int r;
51         spring->nodes = malloc(sizeof(struct Physics)*nodecount);
52         for(r=0;r<nodecount;r++) {
53             init_physobj(&spring->nodes[r],
54                 spring->head->x,spring->head->y,makeVector(0,0));
55             spring->nodes[r].sharpness = BOUNCY;
56         }
57 
58     } else {
59         spring->nodes = NULL;
60     }
61 
62     return spring;
63 }
64 
65 /* Destroy the spring */
free_spring(struct Spring * spring)66 void free_spring(struct Spring *spring) {
67     /* TODO, when tail is another object, it shouldn't be freed */
68     free(spring->tail);
69     free(spring->nodes);
70     free(spring);
71 }
72 
73 /* Animate spring segment */
animate_segment(struct Spring * spring,struct Physics * s1,struct Physics * s2)74 static void animate_segment(struct Spring *spring,struct Physics *s1, struct Physics *s2) {
75     Vector springvec = makeVector(s1->x - s2->x, s1->y - s2->y);
76     double dist = hypot(springvec.x,springvec.y);
77     if(dist>0) {
78         Vector force = multVector(springvec,1/dist);
79         Vector friction = {s1->vel.x - s2->vel.x, s1->vel.y - s2->vel.y};
80 
81         force = multVector(force,(dist - spring->nodelen)*spring->sc);
82         friction = multVector(friction, -0.1); /* Something wrong with this */
83         force = addVectors(force,friction);
84 
85         s1->vel = addVectors(s1->vel,multVector(force,1/(s1->mass/s2->mass)));
86         s2->vel = addVectors(s2->vel,multVector(force,1/(-s2->mass/s1->mass)));
87     }
88 }
89 
90 /* Simulate the spring */
animate_spring(struct Spring * spring)91 void animate_spring(struct Spring *spring) {
92 
93     if(spring->nodes) {
94         int r;
95         animate_segment(spring,spring->head,&spring->nodes[0]);
96         for(r=0;r<spring->nodecount-1;r++) {
97             animate_segment(spring,&spring->nodes[r],&spring->nodes[r+1]);
98             animate_object(&spring->nodes[r],0,NULL);
99         }
100         animate_segment(spring,&spring->nodes[r],spring->tail);
101         animate_object(&spring->nodes[r],0,NULL);
102     } else {
103         animate_segment(spring,spring->head,spring->tail);
104     }
105     animate_object(spring->tail,0,NULL);
106 }
107 
108 /* Draw a spring segment */
draw_segment(Uint32 color,const struct Physics * s1,const struct Physics * s2,const SDL_Rect * camera,const SDL_Rect * viewport)109 static void draw_segment(Uint32 color,const struct Physics *s1,
110         const struct Physics *s2, const SDL_Rect *camera, const SDL_Rect *viewport)
111 {
112     int x1 = Round(s1->x)-camera->x;
113     int y1 = Round(s1->y)-camera->y;
114     int x2 = Round(s2->x)-camera->x;
115     int y2 = Round(s2->y)-camera->y;
116 
117     if(clip_line(&x1,&y1,&x2,&y2, 0, 0, camera->w,camera->h))
118         draw_line(screen,x1+viewport->x,y1+viewport->y,
119                 x2+viewport->x,y2+viewport->y,color);
120 }
121 
122 /* Draw the spring onto screen */
draw_spring(struct Spring * spring,const SDL_Rect * camera,const SDL_Rect * viewport)123 void draw_spring(struct Spring *spring, const SDL_Rect *camera, const SDL_Rect *viewport) {
124     if(spring->nodes) {
125         int r;
126         draw_segment(spring->color,spring->head,&spring->nodes[0],camera,viewport);
127         for(r=0;r<spring->nodecount-1;r++) {
128             draw_segment(spring->color,&spring->nodes[r],
129                     &spring->nodes[r+1],camera,viewport);
130         }
131         draw_segment(spring->color,&spring->nodes[r],
132                 spring->tail,camera,viewport);
133     } else {
134         draw_segment(spring->color,spring->head,spring->tail,camera,viewport);
135     }
136 }
137 
138