Rev 127 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
#include "ball.h"
#include "mondrian.h"
#include "console.h"
#include "utils.h"
#include "vector2d.h"
#include <utility>
using namespace std;
extern mondrian mondrian0;
extern float PI_BY_180;
ball::ball (float _x, float _y, rect* _R) : x(_x), y(_y), R(_R) {init ();}
ball::ball (int _type) : trail (1, 10) { init (_type); }
void ball::init (int _type) {
V = 0;
vx = vy = 0;
select = 0;
frozen = 1;
pitch_mult = 1;
vol_mult = 1;
mod = 0;
r = g = b = 0.75f;
attack_time = recent_attack_time;
decay_time = recent_decay_time;
num_notes = 0;
del = 0;
auto_rotate = 0;
dtheta = PI_BY_180;
set_type (_type);
++ref;
}
void ball::set_velocity (float dx, float dy) {
V = unit_vector (vx, vy, dx, dy);
if (V == 0) {
vx = 1;
vy = 1;
V = unit_vector (vx, vy, vx, vy);
}
calc_velocity_slope ();
}
void ball::rotate_velocity (int dir) {
rotate_vector (vx, vy, dir * dtheta);
calc_velocity_slope ();
}
void ball::calc_velocity_slope () {
if (vx != 0) {
vm = vy * 1.0f / vx;
vm_1 = 1.0f / vm;
vm_inf = 0;
} else {
vm = 0.0f;
vm_1 = 0.0f;
vm_inf = 1;
}
}
void ball::on_edge_hit (int e1, int e2, int cl, float& v, float xry, float yrx, float elb, float ewh, pair<float, float>& invl, int& eh) {
eh = 1;
int walle [] = {e1, 0, e2};
slit* S = 0;
rect* RO = get_other_rect_of_slit (R, walle[cl+1], xry, &S);
if (RO) { // ball in slit
eh = 0; // edge hit didnt happen
if (type == HEALER) mondrian0.remove_slit (S); // close slit
R->erase (this);
R = RO; // ball is now in other box
R->balls.push_back (this);
} else { // ball hit edge
if (type == WRECKER) {
if (mondrian0.slitting == mondrian::ANIMATE_SLIT) {
mondrian0.fdr.restart ();
mondrian0.add_remove_slit (x, y, &mondrian0.fdr); // make animated slit
}
else
mondrian0.add_remove_slit (x, y); // make slit
}
v = -v; // flip component of velocity to rebound
calc_velocity_slope ();
float xy, t0, dt;
xy = yrx;
t0 = elb;
dt = ewh;
mondrian0.launch_note (this, xy, t0, dt, invl);
}
}
void ball::update () {
int edge_hit = 0;
if (!frozen) {
trail.add (x, y);
float px = x, py = y; // prev position
// move the ball by a constant speed we found when user made the ball
x += (V * vx);
y += (V * vy);
box<float>& e = R->extents; // get the box the ball is bouncing in
box<float>& eroot = mondrian0.root->extents; // get the root box
// check if the ball is still inside this box after move
if (inbox (e, x, y)) {
// ball is still inside the box so theres nothing to do
} else { // ball has hit a wall or ceiling of box
float ix = x, iy = y;
int clx = clamp<float> (e.left, x, e.right);
if (clx) { // hit wall
if (vm_inf == 0) y = py + vm * (x - px); else y = py;
if (clamp (e.bottom, y, e.top)) { x = ix; y = iy; goto tryy;}
on_edge_hit (edge::LEFT, edge::RIGHT, clx, vx, y, x, eroot.left, eroot.width_1, R->vint, edge_hit);
/*int walle [] = {edge::LEFT, 0, edge::RIGHT};
slit* S = 0;
rect* RO = get_other_rect_of_slit (R, walle[clx+1], y, &S);
if (RO) { // ball in the slit
if (type == HEALER) {
mondrian0.remove_slit (S); // close slit
//mondrian0.marks.push_back (point<float>(x, y));
}
R->erase (this);
R = RO; // ball is now in other box
R->balls.push_back (this);
edge_hit = 0;
} else { // ball not in slit
if (type == WRECKER) mondrian0.add_remove_slit (x, y); // make slit
vx = -vx; // flip horizontal component of velocity to rebound
calc_velocity_slope ();
xy = x;
t0 = eroot.left;
dt = eroot.width_1;
mondrian0.launch_note (this, xy, t0, dt, R->vint);
}*/
} else {
tryy:
int cly = clamp<float> (e.bottom, y, e.top);
if (cly) { // hit floor or ceiling
if (vm_inf == 0) x = px + vm_1 * (y - py); else x = px;
on_edge_hit (edge::BOTTOM, edge::TOP, cly, vy, x, y, eroot.bottom, eroot.height_1, R->hint, edge_hit);
//clamp (e.left, x, e.right);
/*int walle [] = {edge::BOTTOM, 0, edge::TOP};
slit* S = 0;
rect* RO = get_other_rect_of_slit (R, walle[cly+1], x, &S);
if (RO) { // ball in the slit
if (type == HEALER) {
mondrian0.remove_slit (S);
//mondrian0.marks.push_back (point<float>(x,y));
}
R->erase (this);
R = RO;
R->balls.push_back (this); // ball is now in other box
edge_hit = 0;
} else {
if (type == WRECKER) mondrian0.add_remove_slit (x, y); // make slit
vy = -vy; // flip vertical component of velocity to rebound
calc_velocity_slope ();
xy = y;
t0 = eroot.bottom;
dt = eroot.height_1;
mondrian0.launch_note (this, xy, t0, dt, R->hint);
}*/
}
}
}
}
if (auto_rotate && !edge_hit) rotate_velocity (auto_rotate); // auto_rotate = -1 is clockwise; auto_rotate = 1 is anti-clockwise
}
void ball::set_type (int T) {
type = T;
switch (type) {
case ball::BOUNCER:
color_using_modulation ();
break;
case ball::WRECKER:
r = 1.0f; g = 0.25f; b = 0.25f;
break;
case ball::HEALER:
r = 0.0f; g = 1.0f; b = 1.0f;
}
}
void ball::color_using_modulation () {
if (type != ball::BOUNCER) return;
if (mod < 0) {
r = g = b = 0.15f;
} else if (mod > 0) {
r = g = b = 1.0f;
} else {
r = g = b = 0.60f;
}
}