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