第10組
From PlayAroundWiki
Contents |
成員
輔導員:沈聖博
第一次作品概念
- 多媒體塗鴉
希望藉由學到的互動媒體,去表現塗鴉創作的樂趣。 組裝一個電子裝置,模擬一個噴漆罐,但是這個噴漆罐不只可以噴出色彩(利用投影+wiimote),也能噴出聲音。 而且搖動它還可以換色(利用tilt tilt switch)。 混色與混音可即時產生。
製作過程中遇到到問題
通常都是軟體的整合以及相容性的問題
因為我們同時使用PD,Ardrino,Processing還要使用OSC作溝通,wiimote的Library匯入也很多奇怪的問題
有機會還是希望能繼續修改
(使感應準確一點)
最終作品概念
- 名稱:Shaking Your Color
- 說明:
- 這是一個影子可以隨意揮灑色彩的世界。在黑白的世界中,影子能隨意地塗鴉!
- 透過一個自製的噴漆罐,影子不但能噴出色彩,也能噴出聲音,搖動它還可以換色。
- 混色與混音的歡愉,讓影子在黑白的世界中跳舞!
- 但色彩畢竟無法存在於黑白的世界,噴灑出的彩色圓點,會隨著時間慢慢淡化直至消失。
- 使用媒材:
- Mac筆記電腦 x1、自製噴漆罐 x1、Wii搖桿 x1、紅外線LED燈 x3、Arduino I/O板 x1、麵包板 x1、跳線包 x 1、按鍵開關 x1、三軸加速器 x1、投影機 x1、喇叭組 x1
- 使用程式:
- Arduino(讀取三軸加速器即時資訊)、Processing (噴漆畫面呈現)、darwiinremoteOSC library(與Processing配合,以讀取Wii搖控器動態即時資料)、PureData (讀取Arduino及Processing送過來的動態即時資料,以產生聲音)、OSC protocal (作為Wii搖控器、Processing及PureData三者之間的溝通協定)
幕後花絮
P.S影片因拍攝用相機為早期機種無收音功能,請大家不要誤認為自己的音響喇叭壞了。
- 以下此段影片為作品製作中測試軟體連接溝通成效情形的側拍
- 以下此段影片在測試紅外線LED燈透過投影布幕能夠被wiimote接收的成效如何,以及在電腦上的軟體能否即時反應。
- 以下此段影片是以另一角度拍攝測試情況,畫面中電腦螢幕顯示出移動的白色圓點,即是反應紅外線LED燈的移動位置。
- 以下這段影片為在交大浩然國際會議廳實際展演前的測試,很可惜無法收音,因為小組成員利用了PD軟體做了好幾段的電子聲音,供噴漆時用,且會隨著按壓噴漆、及搖晃噴漆罐瓶身發出不同的聲音效果。投影布幕上噴灑出的彩色原點,會隨著時間慢慢淡化直至消失,表現出街頭塗鴉作品難以永久保存,很快就會被新的創作者作品覆蓋的意涵。
作品檔案
- arduino 所用檔案
/*
* Copyright (C) 2006 Free Software Foundation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * See file LICENSE for further informations on licensing terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * ----------------------------------------------------------- * Firmata, the general purpose sensorbox firmware for Arduino * ----------------------------------------------------------- * * Firmata turns the Arduino into a Plug-n-Play sensorbox, servo * controller, and/or PWM motor/lamp controller. * * It was originally designed to work with the Pd object [arduino] * which is included in Pd-extended. This firmware is intended to * work with any host computer software package. It can easily be * used with other programs like Max/MSP, Processing, or whatever can * do serial communications. * * @author: Hans-Christoph Steiner <hans@at.or.at> * help with initial protocol redesign: Jamie Allen <jamie@heavyside.net> * much protocol discussion: the Arduino developers mailing list * key bugfixes: Georg Holzmann <grh@mur.at> * Gerda Strobl <gerda.strobl@student.tugraz.at> * @date: 2006-05-19 * @locations: STEIM, Amsterdam, Netherlands * IDMI/Polytechnic University, Brookyn, NY, USA * Electrolobby Ars Electronica, Linz, Austria */
/*
* TODO: add pulseOut functionality for servos * TODO: add software PWM for servos, etc (servo.h or pulse.h) * TODO: add device type reporting (i.e. some firmwares will use the Firmata * protocol, but will only support specific devices, like ultrasound * rangefinders or servos) * TODO: use Program Control to load stored profiles from EEPROM */
/* cvs version: $Id: Pd_firmware.pde,v 1.29 2007/03/08 05:37:22 eighthave Exp $ */
/*==============================================================================
* MESSAGE FORMATS *============================================================================*/
/* -----------------------------------------------------------------------------
* MAPPING DATA TO MIDI * * This protocol uses the MIDI message format, but does not use the whole * protocol. Most of the command mappings here will not be directly usable in * terms of MIDI controllers and synths. It should co-exist with MIDI without * trouble and can be parsed by standard MIDI interpreters. Just some of the * message data is used differently. * * MIDI format: http://www.harmony-central.com/MIDI/Doc/table1.html * * MIDI * type command channel first byte second byte * ----------------------------------------------------------------------------- * analog I/O 0xE0 pin # LSB(bits 0-6) MSB(bits 7-13) * digital I/O 0x90 port base LSB(bits 0-6) MSB(bits 7-13) * report analog pin 0xC0 pin # disable/enable(0/1) - n/a - * report digital ports 0xD0 port base disable/enable(0/1) - n/a - * * digital pin mode(I/O) 0xF4 - n/a - pin # (0-63) pin state(0=in) * firmware version 0xF9 - n/a - minor version major version * system reset 0xFF - n/a - - n/a - - n/a - * */
/* proposed extensions using SysEx
* * type SysEx start command data bytes SysEx stop * ----------------------------------------------------------------------------- * pulse I/O 0xF0 0xA0 five 7-bit chunks, LSB first 0xF7 * shiftOut 0xF0 0xF5 dataPin; clockPin; 7-bit LSB; 7-bit MSB 0xF7 */
/* -----------------------------------------------------------------------------
* DATA MESSAGE FORMAT */
/* two byte digital data format
* ---------------------------- * 0 digital data, 0x90-0x9F, (MIDI NoteOn, but different data usage) * 1 digital pins 0-6 bitmask * 2 digital pins 7-13 bitmask */
/* analog 14-bit data format
* ------------------------- * 0 analog pin, 0xE0-0xEF, (MIDI Pitch Wheel) * 1 analog least significant 7 bits * 2 analog most significant 7 bits */
/* version report format
* Send a single byte 0xF9, Arduino will reply with: * ------------------------------------------------- * 0 version report header (0xF9) (MIDI Undefined) * 1 minor version (0-127) * 2 major version (0-127) */
/* pulseIn/Out (uses 32-bit value)
* ------------------------------- * 0 START_SYSEX (0xF0) (MIDI System Exclusive) * 1 pulseIn/Out (0xA0-0xAF) * 2 bits 0-6 (least significant byte) * 3 bits 7-13 * 4 bits 14-20 * 5 bits 21-27 * 6 bits 28-34 (most significant byte) * 7 END_SYSEX (0xF7) (MIDI End of SysEx - EOX) */
/* shiftIn/Out (uses 8-bit value)
* ------------------------------ * 0 START_SYSEX (0xF0) * 1 shiftOut (0xF5) * 2 dataPin (0-127) * 3 clockPin (0-127) * 4 bits 0-6 (least significant byte) * 5 bit 7 (most significant bit) * 6 END_SYSEX (0xF7) */
/* -----------------------------------------------------------------------------
* CONTROL MESSAGES */
/* set digital pin mode
* -------------------- * 1 set digital pin mode (0xF4) (MIDI Undefined) * 2 pin number (0-127) * 3 state (INPUT/OUTPUT, 0/1) */
/* toggle analogIn reporting by pin
* -------------------------------- * 0 toggle digitalIn reporting (0xC0-0xCF) (MIDI Program Change) * 1 disable(0)/enable(non-zero) */
/* toggle digitalIn reporting by port pairs
* ---------------------------------------- * 0 toggle digitalIn reporting (0xD0-0xDF) (MIDI Aftertouch) * 1 disable(0)/enable(non-zero) */
/* request version report
* ---------------------- * 0 request version report (0xF9) (MIDI Undefined) */
/*==============================================================================
* MACROS *============================================================================*/
/* Version numbers for the protocol. The protocol is still changing, so these
* version numbers are important. This number can be queried so that host * software can test whether it will be compatible with the currently * installed firmware. */
- define FIRMATA_MAJOR_VERSION 1 // for non-compatible changes
- define FIRMATA_MINOR_VERSION 0 // for backwards compatible changes
/* total number of pins currently supported */
- define TOTAL_ANALOG_PINS 6
- define TOTAL_DIGITAL_PINS 14
// for comparing along with INPUT and OUTPUT
- define PWM 2
// for selecting digital inputs
- define PB 2 // digital input, pins 8-13
- define PC 3 // analog input port
- define PD 4 // digital input, pins 0-7
- define MAX_DATA_BYTES 2 // max number of data bytes in non-SysEx messages
/* message command bytes */
- define DIGITAL_MESSAGE 0x90 // send data for a digital pin
- define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM)
//#define PULSE_MESSAGE 0xA0 // proposed pulseIn/Out message (SysEx) //#define SHIFTOUT_MESSAGE 0xB0 // proposed shiftOut message (SysEx)
- define REPORT_ANALOG_PIN 0xC0 // enable analog input by pin #
- define REPORT_DIGITAL_PORTS 0xD0 // enable digital input by port pair
- define START_SYSEX 0xF0 // start a MIDI SysEx message
- define SET_DIGITAL_PIN_MODE 0xF4 // set a digital pin to INPUT or OUTPUT
- define END_SYSEX 0xF7 // end a MIDI SysEx message
- define REPORT_VERSION 0xF9 // report firmware version
- define SYSTEM_RESET 0xFF // reset from MIDI
/*==============================================================================
* GLOBAL VARIABLES *============================================================================*/
/* input message handling */ byte waitForData = 0; // this flag says the next serial input will be data byte executeMultiByteCommand = 0; // execute this after getting multi-byte data byte multiByteChannel = 0; // channel data for multiByteCommands byte storedInputData[MAX_DATA_BYTES] = {0,0}; // multi-byte data /* digital pins */ boolean digitalInputsEnabled = false; // output digital inputs or not int digitalInputs; int previousDigitalInputs; // previous output to test for change int digitalPinStatus = 3; // bitwise array to store pin status, ignore RxTx pins /* PWM/analog outputs */ int pwmStatus = 0; // bitwise array to store PWM status /* analog inputs */ unsigned int analogPinsToReport = 0; // bitwise array to store pin reporting int analogPin = 0; // counter for reading analog pins int analogData; // storage variable for data from analogRead() /* timer variables */ extern volatile unsigned long timer0_overflow_count; // timer0 from wiring.c unsigned long nextExecuteTime; // for comparison with timer0_overflow_count
/*==============================================================================
* FUNCTIONS *============================================================================*/
/* -----------------------------------------------------------------------------
* output the version message to the serial port */
void printVersion() {
Serial.print(REPORT_VERSION, BYTE); Serial.print(FIRMATA_MINOR_VERSION, BYTE); Serial.print(FIRMATA_MAJOR_VERSION, BYTE);
}
/* -----------------------------------------------------------------------------
* output digital bytes received from the serial port */
void outputDigitalBytes(byte pin0_6, byte pin7_13) {
int i; int mask; int twoBytesForPorts;
// this should be converted to use PORTs
twoBytesForPorts = pin0_6 + (pin7_13 << 7);
for(i=2; i<TOTAL_DIGITAL_PINS; ++i) { // ignore Rx,Tx pins (0 and 1)
mask = 1 << i;
if( (digitalPinStatus & mask) && !(pwmStatus & mask) ) {
digitalWrite(i, twoBytesForPorts & mask ? HIGH : LOW);
}
}
}
/* -----------------------------------------------------------------------------
* check all the active digital inputs for change of state, then add any events * to the Serial output queue using Serial.print() */
void checkDigitalInputs(void) {
if(digitalInputsEnabled) {
previousDigitalInputs = digitalInputs; digitalInputs = PINB << 8; // get pins 8-13 digitalInputs += PIND; // get pins 0-7 digitalInputs = digitalInputs &~ digitalPinStatus; // ignore pins set OUTPUT if(digitalInputs != previousDigitalInputs) { // TODO: implement more ports as channels for more than 16 digital pins Serial.print(DIGITAL_MESSAGE,BYTE); Serial.print(digitalInputs % 128, BYTE); // Tx pins 0-6 Serial.print(digitalInputs >> 7, BYTE); // Tx pins 7-13 }
}
}
// ----------------------------------------------------------------------------- /* sets the pin mode to the correct state and sets the relevant bits in the
* two bit-arrays that track Digital I/O and PWM status */
void setPinMode(byte pin, byte mode) {
if(pin > 1) { // ignore RxTx pins (0,1)
if(mode == INPUT) { digitalPinStatus = digitalPinStatus &~ (1 << pin); pwmStatus = pwmStatus &~ (1 << pin); digitalWrite(pin,LOW); // turn off pin before switching to INPUT pinMode(pin,INPUT); } else if(mode == OUTPUT) { digitalPinStatus = digitalPinStatus | (1 << pin); pwmStatus = pwmStatus &~ (1 << pin); pinMode(pin,OUTPUT); } else if( mode == PWM ) { digitalPinStatus = digitalPinStatus | (1 << pin); pwmStatus = pwmStatus | (1 << pin); pinMode(pin,OUTPUT); }
// TODO: save status to EEPROM here, if changed }
}
// ----------------------------------------------------------------------------- /* sets bits in a bit array (int) to toggle the reporting of the analogIns
*/
void setAnalogPinReporting(byte pin, byte state) {
if(state == 0) {
analogPinsToReport = analogPinsToReport &~ (1 << pin);
}
else { // everything but 0 enables reporting of that pin
analogPinsToReport = analogPinsToReport | (1 << pin);
}
// TODO: save status to EEPROM here, if changed
}
/* -----------------------------------------------------------------------------
* processInput() is called whenever a byte is available on the * Arduino's serial port. This is where the commands are handled. */
void processInput(int inputData) {
int command;
// a few commands have byte(s) of data following the command
if( (waitForData > 0) && (inputData < 128) ) {
waitForData--;
storedInputData[waitForData] = inputData;
if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message
switch(executeMultiByteCommand) {
case ANALOG_MESSAGE:
setPinMode(multiByteChannel,PWM); analogWrite(multiByteChannel, (storedInputData[0] << 7) + storedInputData[1] );
break;
case DIGITAL_MESSAGE:
outputDigitalBytes(storedInputData[1], storedInputData[0]); //(LSB, MSB) break;
case SET_DIGITAL_PIN_MODE:
setPinMode(storedInputData[1], storedInputData[0]); // (pin#, mode) if(storedInputData[0] == INPUT) digitalInputsEnabled = true; // enable reporting of digital inputs
break;
case REPORT_ANALOG_PIN:
setAnalogPinReporting(multiByteChannel,storedInputData[0]);
break;
case REPORT_DIGITAL_PORTS:
// TODO: implement MIDI channel as port base for more than 16 digital inputs if(storedInputData[0] == 0) digitalInputsEnabled = false; else digitalInputsEnabled = true;
break;
}
executeMultiByteCommand = 0;
}
} else {
// remove channel info from command byte if less than 0xF0
if(inputData < 0xF0) {
command = inputData & 0xF0;
multiByteChannel = inputData & 0x0F;
} else {
command = inputData;
// commands in the 0xF* range don't use channel data
}
switch (command) { // TODO: these needs to be switched to command
case ANALOG_MESSAGE:
case DIGITAL_MESSAGE:
case SET_DIGITAL_PIN_MODE:
waitForData = 2; // two data bytes needed
executeMultiByteCommand = command;
break;
case REPORT_ANALOG_PIN:
case REPORT_DIGITAL_PORTS:
waitForData = 1; // two data bytes needed
executeMultiByteCommand = command;
break;
case SYSTEM_RESET:
// this doesn't do anything yet
break;
case REPORT_VERSION:
printVersion();
break; } }
}
/* -----------------------------------------------------------------------------
* this function checks to see if there is data waiting on the serial port * then processes all of the stored data */
void checkForSerialReceive() {
while(Serial.available())
processInput(Serial.read()); }
// ============================================================================= // used for flashing the pin for the version number void pin13strobe(int count, int onInterval, int offInterval) {
byte i;
pinMode(13, OUTPUT);
for(i=0; i<count; i++) {
delay(offInterval);
digitalWrite(13,1);
delay(onInterval);
digitalWrite(13,0);
}
}
/*==============================================================================
* SETUP() *============================================================================*/
void setup() {
byte i;
Serial.begin(57600); // 9600, 14400, 38400, 57600, 115200
// flash the pin 13 with the protocol version pinMode(13,OUTPUT); pin13strobe(2,1,4); // separator, a quick burst delay(500); pin13strobe(FIRMATA_MAJOR_VERSION, 200, 400); delay(500); pin13strobe(2,1,4); // separator, a quick burst delay(500); pin13strobe(FIRMATA_MINOR_VERSION, 200, 400); delay(500); pin13strobe(2,1,4); // separator, a quick burst
for(i=0; i<TOTAL_DIGITAL_PINS; ++i) {
setPinMode(i,INPUT);
}
// TODO: load state from EEPROM here
printVersion();
/* TODO: send digital inputs here, if enabled, to set the initial state on the * host computer, since once in the loop(), the Arduino will only send data on * change. */
}
/*==============================================================================
* LOOP() *============================================================================*/
void loop() { /* DIGITALREAD - as fast as possible, check for changes and output them to the
* FTDI buffer using Serial.print() */
checkDigitalInputs();
if(timer0_overflow_count > nextExecuteTime) {
nextExecuteTime = timer0_overflow_count + 19; // run this every 20ms /* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle * all serialReads at once, i.e. empty the buffer */ checkForSerialReceive(); /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over * 60 bytes. use a timer to sending an event character every 4 ms to * trigger the buffer to dump. */
/* ANALOGREAD - right after the event character, do all of the * analogReads(). These only need to be done every 4ms. */ for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) { if( analogPinsToReport & (1 << analogPin) ) { analogData = analogRead(analogPin); Serial.print(ANALOG_MESSAGE + analogPin, BYTE); // These two bytes converted back into the 10-bit value on host Serial.print(analogData % 128, BYTE); Serial.print(analogData >> 7, BYTE); } }
}
}
- processing 所用檔案
/**
* osc, processing and the wiimote, using darwiinremoteOSC * for comments or questions contact andreas schlegel, andi@sojamo.de */
import oscP5.*; import netP5.*; import traer.physics.*;
//particle system ParticleSystem physics; ParticleSystem physics2; Particle last; Particle last2;
//drawing related float r=33; float g=33; float b=33; int buttonStatus = 1; //0 or 1 boolean changeSpryColor=false; //check if change spry color float xxc=0.5; float yyc=0.5; float zzc=0.5; float xxp=0.5; float yyp=0.5; float zzp=0.5;
//OSC OscP5 osc; NetAddress myRemoteLocation; float[] ir; boolean DEBUG;
int gcCounter = 0; int gcCounterFinal = 1000;
void setup() { // size(800, 600, P3D);
size(1024, 768);
// frameRate(25);
// open an udp port for listening to incoming osc messages from darwiinremoteOSC osc = new OscP5(this, 6666); //open local port: 6666
osc.plug(this,"ir","/wii/irdata"); osc.plug(this,"connected","/wii/connected");
ir = new float[12];
//myRemoteLocation = new NetAddress("192.168.11.29", 6667); //connect to remote host and port:6667
myRemoteLocation = new NetAddress("127.0.0.1", 6668); //connect to remote host and port:6667
noStroke();
fill( 255, 222 ); physics = new ParticleSystem(-0.0001, 0.1); physics2 = new ParticleSystem(0.0001, 0.1); ellipseMode( CENTER ); noCursor();
}
void connected(int theFlag) {
if(theFlag==1) {
println("wii connected");
}
else {
println("wii DISCONNECTED");
}
}
// darwiinremoteOSC sends 12 floats containing the x,y and size values for // 4 IR spots the wiimote can sense. values are between 0 and 1 for x and y // values for size are 0 and bigger. if the size is 15 or 0, the IR point is not // recognized by the wiimote. void ir( float f10, float f11,float f12, float f20,float f21, float f22, float f30, float f31, float f32, float f40, float f41, float f42 ) {
ir[0] = f10; ir[1] = f11; ir[2] = f12; ir[3] = f20; ir[4] = f21; ir[5] = f22; ir[6] = f30; ir[7] = f31; ir[8] = f32; ir[9] = f40; ir[10] = f41; ir[11] = f42;
}
void draw() {
background(255);
if (buttonStatus==1){
if(ir[0]!=1 && ir[1]!=1){
changeSpryColor = false;
drawSomething();
sendOSC(1);
println("draw...");
}else{
changeSpryColor = true;
sendOSC(0);
println("change color ...");
}
}else{
changeSpryColor = false;
// changeSpryColor = true;
sendOSC(0); }
physics.tick(); physics2.tick(); fill(r, g, b); rect(0,height-10,width,10); noStroke();
for ( int i = 0; i < physics.numberOfParticles(); ++i )
{
Particle p = physics.getParticle( i );
// Particle pa = physics.getParticle( i+1 );
Particle p2 = physics2.getParticle( i );
// fill( r,g,b, 255/(p.age()/10+1) );
fill( r,g,b, 255/(p.age()+1) );
ellipse( p.position().x(), p.position().y(), random(6, 22), random(6, 24) );
// line(p.position().x(), p.position().y(), pa.position().x(), pa.position().y()); // fill( 255,0,0, 255/(p2.age()/10+1) );
fill( 255,0,0, 255/(p2.age()+1) );
ellipse( p2.position().x(), p2.position().y(), random(6, 22), random(6, 12) );
}
delay(50);
gcCounter = gcCounter + 1;
if(gcCounter > gcCounterFinal){
gcCounter = 0;
System.gc();
}
}
void sendOSC(int IRnumber) {
/* in the following different ways of creating osc messages are shown by example */
OscMessage myMessage = new OscMessage("/wiiData");
//myMessage.add(X);
//myMessage.add(Y);
myMessage.add(IRnumber);
/* send the message */
osc.send(myMessage, myRemoteLocation);
}
/* incoming osc messf are forwarded to the oscEvent method. */
void oscEvent(OscMessage theOscMessage) {
/* print the address pattern and the typetag of the received OscMessage */
print("### received an osc message.");
print(" addrpattern: "+theOscMessage.addrPattern());
println(" typetag: "+theOscMessage.typetag());
if(theOscMessage.addrPattern().equals("/wii/irdata")){
ir[0]=theOscMessage.get(0).floatValue();
ir[1]=theOscMessage.get(1).floatValue();
println("ir[0] = "+theOscMessage.get(0).floatValue());
println("ir[1] = "+theOscMessage.get(1).floatValue());
println("ir[2] = "+theOscMessage.get(2).floatValue());
}
if(theOscMessage.addrPattern().equals("/PDMessage")){
xxc = theOscMessage.get(0).floatValue();
yyc = theOscMessage.get(1).floatValue();
zzc = theOscMessage.get(2).floatValue();
buttonStatus = theOscMessage.get(3).intValue();
println(" osc string: "+xxc);
println(" osc string: "+yyc);
println(" osc string: "+zzc);
println(" osc string: "+buttonStatus);
}
if(changeSpryColor){
if(abs(xxc-xxp)>0.01){
r=r+10;
if(r>255){
r=0;
}
}
if(abs(yyc-yyp)>0.01){
g=g+10;
if(g>255){
g=0;
}
}
if(abs(zzc-zzp)>0.01){
b=b+10;
if(b>255){
b=0;
}
}
}
}
void drawSomething(){
fill(r,g,b);
ellipse(ir[0]*width, ir[1]*height, 6, 6);
println("ir ("+ir[0]*width+", "+ir[1]*height+")");
//physics.clear();
//physics2.clear();
for ( int i = 0; i < 10; i++ )
{
Particle p = physics.makeParticle( 0.9f, ir[0]*width, ir[1]*height, 0 );
Particle p2 = physics2.makeParticle( 0.95f, ir[0]*width, ir[1]*height, 0 );
p.setVelocity( random( -1, 1 ), random( -0.5, -1 ), 0 );
p2.setVelocity( random( -1, 1 ), random( 0.5, 1 ), 0 );
if ( last != null ){
physics.makeSpring( p, last, 0.5f, 0.1f, 10 );
}
if ( last2 != null ){
physics2.makeSpring( p2, last2, 0.5f, 1.0f, 10 );
}
last = p;
last2 = p2 ;
}
}
