joshua
/
beats-sim
Archived

### copied source from Gravity Beats

master
Joshua Moerman 11 years ago
parent
commit
61c889b0c6
5 changed files with 491 additions and 0 deletions
1. 86
Beat.h
2. 99
Math.h
3. 70
Scales.h
4. 211
Simulation.h
5. 25
UserInformation.h

#### 86 Beat.h View File

 `@ -0,0 +1,86 @@` ```// ``` ```// Beat.h ``` ```// GravityBeats ``` ```// ``` ```// Created by Joshua Moerman on 1/9/13. ``` ```// Copyright (c) 2013 Vadovas. All rights reserved. ``` ```// ``` ``` ``` `#ifndef GravityBeats_Beat_h` `#define GravityBeats_Beat_h` ``` ``` `#include ` `#include ` ``` ``` `#include "UserInformation.h"` ``` ``` `template ` `struct Note : public UserInformation{` ``` // see http://en.wikipedia.org/wiki/Note_value ``` ` enum Speed {` ``` kWholeNote =1, // 1 in one measure ``` ``` kHalfNote =2, // 2 in one measure ``` ``` kTriplet =3, // 3 in one measure ``` ``` kQuarterNote =4, // 4 ``` ``` kHalfTriplet =6, // 6 ``` ``` kEighthNote =8 // 8 ``` ` } speed;` ` int progress = -2;` ` ` ` template ` ` Note(Speed speed, S... args)` ` : UserInformation(args...)` ` , speed(speed)` ` {}` ` ` ``` // we could return how much it is off, to give the balls the right initial position and speed. ``` ` bool update(float time_in_measure){` ` int new_progress = std::floor(time_in_measure*speed);` ` if(new_progress != progress){` ` if(progress == -2){` ` progress = new_progress;` ` return false;` ` } else {` ` progress = new_progress;` ` return true;` ` }` ` }` ` return false;` ` }` ` ` ` void reset(){` ` progress = -1;` ` }` `};` ``` ``` `template ` `struct Beat {` ``` float total_length{4.0}; // 60 bpm ``` ` float time{-0.1};` ` ` ` std::vector> notes;` ` ` ` std::vector update(float dt){` ` std::vector ret;` ` time += dt;` ` ` ``` // not needed, but keeps the floats small ``` ``` // also usefull when we want to change bpm ``` ` if(time > total_length){` ` time -= total_length;` ` for(auto& n : notes){` ` n.reset();` ` }` ` }` ` ` ` for(auto& n : notes){` ` if(n.update(time / total_length)){` ` ret.push_back(n.information);` ` }` ` }` ` ` ` return ret;` ` }` `};` ``` ``` `#endif`

#### 99 Math.h View File

 `@ -0,0 +1,99 @@` ```// ``` ```// Math.h ``` ```// GravityBeats ``` ```// ``` ```// Created by Joshua Moerman on 1/12/13. ``` ```// Copyright (c) 2013 Vadovas. All rights reserved. ``` ```// ``` ``` ``` `#ifndef GravityBeats_Math_h` `#define GravityBeats_Math_h` ``` ``` `#include ` ``` ``` `namespace math {` ` struct Vec2 {` ` float x, y;` ` ` ` Vec2& operator *= (float rh){` ` x *= rh;` ` y *= rh;` ` return *this;` ` }` ` ` ` Vec2& operator+= (Vec2 const & rh){` ` x += rh.x;` ` y += rh.y;` ` return *this;` ` }` ` ` ` float sqr_length() const {` ` return x*x + y*y;` ` }` ` ` ` float length() const {` ` return std::sqrt(sqr_length());` ` }` ` ` ` Vec2& normalize(){` ` const float l = length();` ` if(l == 0.0f) { return *this; }` ` x /= l;` ` y /= l;` ` return *this;` ` }` ` };` ` ` ` inline Vec2 operator*(float lh, Vec2 rh){` ` rh *= lh;` ` return rh;` ` }` ` ` ` inline Vec2 operator+(Vec2 lh, Vec2 const & rh){` ` return lh += rh;` ` }` ` ` ` inline Vec2 operator-(Vec2 lh, Vec2 const & rh){` ` return lh += -1.0*rh;` ` }` ` ` ` inline float dot(Vec2 const & lh, Vec2 const & rh){` ` return lh.x*rh.x + lh.y*rh.y;` ` }` ` ` ` inline Vec2 rotate_ccw(Vec2 v){` ` std::swap(v.x, v.y);` ` v.x *= -1.0;` ` return v;` ` }` ` ` ` inline Vec2 normalize(Vec2 v){` ` return v.normalize();` ` }` ` ` ` inline float distance_point_point(Vec2 p1, Vec2 p2){` ` return (p2 - p1).length();` ` }` ` ` ``` // p point, [v,w] line segment ``` ` inline float distance_point_line(Vec2 p, Vec2 v, Vec2 w){` ``` // http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment ``` ` const float l2 = (v-w).sqr_length();` ` if (l2 == 0.0) return distance_point_point(p, v);` ``` ``` ` const float t = dot(p - v, w - v) / l2;` ` if (t < 0.0) return distance_point_point(p, v);` ` else if (t > 1.0) return distance_point_point(p, w);` ` ` ` auto projection = v + t * (w - v);` ` return distance_point_point(p, projection);` ` }` ` ` ` template ` ` constexpr T clamp(T input, T min, T max){` ` return input > max ? max :` ` input < min ? min : input;` ` }` `}` ``` ``` `#endif`

#### 70 Scales.h View File

 `@ -0,0 +1,70 @@` ```// ``` ```// Scales.h ``` ```// GravityBeats ``` ```// ``` ```// Created by Joshua Moerman on 1/25/13. ``` ```// Copyright (c) 2013 Vadovas. All rights reserved. ``` ```// ``` ``` ``` `#ifndef GravityBeats_Scales_h` `#define GravityBeats_Scales_h` ``` ``` `#include ` `#include ` `#include ` `#include ` `#include ` ``` ``` ```// http://www.phys.unsw.edu.au/jw/notes.html ``` ``` ``` `inline float pitch_for_midi_note(int note){` ``` // we say 440hz is 1 in our units ``` ` float exponent = (note - 69) / 12.0f;` ` return std::pow(2.0f, exponent);` `}` ``` ``` `struct Scale {` ` std::vector notes;` ` ` ` int note_for_length(float length){` ``` // determine note ``` ` length /= 200.0;` ` float note = -std::log(length) / std::log(2.0f) * 12.0f + 69.0f;` ` ` ``` // determine note in scale ``` ` auto it = notes.begin();` ` while(*it < note && it != notes.end()){` ` ++it;` ` }` ` ` ``` // determine closest note in scale ``` ` if(it == notes.begin()){` ` return *it;` ` } else {` ` auto it2 = it - 1;` ` if(std::abs(*it - note) > std::abs(*it2 - note)){` ` return *it2;` ` } else {` ` return *it;` ` }` ` }` ` }` ` ` ` static Scale load_from_file(std::string filename){` ` std::ifstream file(filename);` ` if(!file) throw std::runtime_error("Couldn't open file " + filename);` ` ` ` Scale scale;` ` ` ` int note = 0;` ` while (file >> note) {` ` scale.notes.push_back(note);` ` }` ` ` ` std::sort(scale.notes.begin(), scale.notes.end());` ` ` ` return scale;` ` }` `};` ``` ``` `#endif`

#### 211 Simulation.h View File

 `@ -0,0 +1,211 @@` ```// ``` ```// Simulation.h ``` ```// GravityBeats ``` ```// ``` ```// Created by Joshua Moerman on 1/5/13. ``` ```// Copyright (c) 2013 Vadovas. All rights reserved. ``` ```// ``` ``` ``` `#ifndef GravityBeats_Simulation_h` `#define GravityBeats_Simulation_h` ``` ``` `#include ` `#include ` ``` ``` `#include "Math.h"` `#include "UserInformation.h"` ``` ``` ```// TODO: if not needed, remove forcefield ``` ``` ``` `namespace simulation {` ``` ``` `template ` `struct Ball : public UserInformation {` ` math::Vec2 position{0.0, 0.0};` ` math::Vec2 speed{0.0, 0.0};` ` ` ` template ` ` Ball(float x, float y, float dx, float dy, S... args)` ` : UserInformation(args...)` ` , position{x, y}` ` , speed{dx, dy}` ` {}` `};` ``` ``` `enum LineKind {` ` kFallThrough,` ` kOneWay` `};` ``` ``` `template ` `struct Line : public UserInformation {` ` math::Vec2 starting_point;` ` math::Vec2 end_point;` ` math::Vec2 normal;` ` float sqr_length;` ` LineKind line_kind;` ` ` ` template ` ` Line(math::Vec2 starting_point, math::Vec2 end_point, LineKind line_kind, S... args)` ` : UserInformation(args...)` ` , starting_point(starting_point)` ` , end_point(end_point)` ` , line_kind(line_kind)` ` {` ` update_normal_and_length();` ` }` ` ` ` void update_normal_and_length(){` ` auto dir = end_point - starting_point;` ` normal = normalize(rotate_ccw(dir));` ` sqr_length = dir.sqr_length();` ` }` `};` ``` ``` `template ` `struct CollisionData {` ` Ball ball;` ` Line line;` ` ` ``` // For this trick I need inheriting ctors... Which we dont have yet... ``` ``` //struct : public UserInformation {} ball_information; ``` ``` //struct : public UserInformation {} line_information; ``` ` ` ` CollisionData(Ball const & b, Line const & l)` ` : ball(b), line(l)` ` {}` `};` ``` ``` `struct Bounds{` ` float xmin{0};` ` float xmax{1280};` ` float ymin{0};` ` float ymax{800};` `};` ``` ``` `template ` `struct Simulation {` ` typedef Ball ball_type;` ` typedef Line line_type;` ` typedef CollisionData collision_type;` ` ` ` std::vector balls;` ` std::vector lines;` ` std::vector collisions_in_update;` ` ` ` Bounds bounds;` ` ` ` float collision_timer{0.0};` ` int total_collisions{0};` ` int collisions{0};` ` int collisions_per_second{0};` ` ` ` Simulation(){` ` balls.reserve(500);` ` lines.reserve(10);` ` collisions_in_update.reserve(1000);` ` }` ` ` ` std::vector update(float dt){` ` collisions_in_update.clear();` ` ` ``` // move balls ``` ` for(auto& b : balls){ ` ` b.speed += dt * math::Vec2{0.0f, 50.0f};` ` ` ` float rest_time = collide(b, lines, dt);` ` b.position += rest_time*b.speed;` ` }` ` ` ``` // count collisions per second (per half second) ``` ` collision_timer += dt;` ` if(collision_timer > 0.5){` ` collision_timer -= 0.5;` ` collisions_per_second = collisions * 2;` ` collisions = 0.0;` ` }` ` ` ``` // remove out-of-scene balls ``` ` for(auto it = balls.begin(); it != balls.end();){` ` ball_type & b = *it;` ` if(b.position.y > bounds.ymax || b.position.x < bounds.xmin || b.position.x > bounds.xmax){` ` it = balls.erase(it);` ` } else {` ` ++it;` ` }` ` }` ` ` ` return collisions_in_update;` ` }` ` ` ``` /* ``` ` Part about the collisions` ` */` ` float collision_time(ball_type const & b, line_type const & l){` ``` // -dot(b.pos - l.start) / ... ``` ` return dot(l.starting_point - b.position, l.normal) / dot(b.speed, l.normal);` ` }` ` ` ` std::pair check_collision(ball_type const & b, line_type const & l, float dt){` ` auto t = collision_time(b, l);` ``` // does it collide within the given time? AND does it go the right way? ``` ` if(0 <= t && t <= dt){` ` if(l.line_kind == kOneWay && dot(b.speed, l.normal) > 0.0){` ` return {false, {0,0}};` ` }` ``` // does it collide with the finite line? ``` ` auto collision = b.position + t*b.speed;` ` auto on_line = dot(collision - l.starting_point, l.end_point - l.starting_point);` ` if(0 <= on_line && on_line <= l.sqr_length){` ` return {true, collision};` ` } else {` ` return {false, {0,0}};` ` }` ` } else {` ` return {false, {0,0}};` ` }` ` }` ` ` ` float collide(ball_type& b, std::vector const & lines, float dt, line_type const * ignore = nullptr){` ` line_type const * closest_line = nullptr;` ` math::Vec2 collision{0.0, 0.0};` ` float closeness = 100.0f;` ` ` ` for(auto& l : lines){` ` if(&l == ignore) continue;` ` auto ret = check_collision(b, l, dt);` ` if(ret.first){` ` auto t = collision_time(b, l);` ` ` ` if(0 <= t && t < closeness){` ` closest_line = &l;` ` closeness = t;` ` collision = ret.second;` ` }` ` }` ` }` ` ` ` if(closest_line == nullptr){` ` return dt;` ` } else {` ` ++total_collisions;` ` ++collisions;` ` ` ` b.position = collision;` ` auto const & l = *closest_line;` ` ` ` collisions_in_update.emplace_back(b, l);` ` ` ` if(l.line_kind != kFallThrough){` ` auto b1 = -dot(b.speed, l.normal) * l.normal;` ` b.speed = 2.0*b1 + b.speed;` ` }` ` ` ` return collide(b, lines, dt - closeness, closest_line);` ` }` ` }` `};` ``` ``` `}` ``` ``` `#endif`

#### 25 UserInformation.h View File

 `@ -0,0 +1,25 @@` ```// ``` ```// UserInformation.h ``` ```// GravityBeats ``` ```// ``` ```// Created by Joshua Moerman on 2/19/13. ``` ```// Copyright (c) 2013 Vadovas. All rights reserved. ``` ```// ``` ``` ``` `#ifndef GravityBeats_UserInformation_h` `#define GravityBeats_UserInformation_h` ``` ``` `template ` `struct UserInformation {` ` template ` ` UserInformation(S... args)` ` : information(args...)` ` {}` ` ` ` T information;` `};` ``` ``` `template <>` `struct UserInformation {};` ``` ``` `#endif`