Bike bb;
import processing.candy.*;
import processing.xml.*;
SVG redBike;
SVG frontTire;
boolean introMode = true;
boolean instructionsMode = false;
boolean drawMode = false;
boolean playMode = false;
boolean winMode = false;
boolean crash;
float[] trackShape;
float segLength = 40;
int trackScroll = 0;
int travelDist = 0;
PImage dirt;
PImage title;
PImage instruct;
PFont arial;
float zoom = 1;
float wheelRadius = 7;
int airPoints;
void setup()
{
size(600, 600);
smooth();
stroke(0);
strokeWeight(1);
frameRate(30);
fill(90, 60, 0);
//Assign original shape to track
trackShape = new float [width*2];
for(trackScroll = 0; trackScroll < trackShape.length; trackScroll++)
{
trackShape[trackScroll] = height/2;
//trackShape[trackScroll] = (sin(trackScroll/40.0)*20)+height/2;
}
redBike = new SVG(this, "bike_body.svg");
frontTire = new SVG (this, "bike_tire.svg");
dirt = loadImage("dirt.png");
title = loadImage("title.jpg");
arial = loadFont ("Arial.vlw");
textFont(arial);
}
void draw()
{
//////////////////// DRAW TRACK MODE ////////////////////
if(introMode)
{
image (title, 0, 0);
if((keyPressed) && (key == ENTER))
{
title = loadImage("instruct.jpg");
}
}
if (drawMode)
{
stroke(0);
zoom = 1;
drawTrack();
}
//////////////////// PLAY MODE ////////////////////
if (playMode)
{
background(100, 60, 20);
if(zoom < 4)
zoom += 0.1;
else
zoom = 4;
//////////////////// Zoom with focus on bike's position ////////////////////
for(int i = int(-bb.frontX*(zoom-1)); i < width + bb.frontX; i+= 100)
{
for(int j = int(-bb.frontY*(zoom-1)); j < height+ bb.frontY; j += 100)
image(dirt, i, j);
}
fill (139, 217, 255);
noStroke();
pushMatrix();
beginShape();
vertex(0, 0);
translate(-bb.frontX*(zoom-1), -bb.frontY*(zoom-1)-((wheelRadius-1)*(zoom-1)));
for(int i = 0; i < width-1; i++)
{
vertex(i*zoom, trackShape[i]*zoom);
}
vertex(width*zoom*2, height/2*zoom);
vertex(width*zoom*2, 0);
vertex(0, 0);
endShape();
popMatrix();
if(bb.backX < width)
{ bb.calculate();
bb.display();
}
fill(255);
if(crash)
fill(255, 0, 0);
textFont(arial);
textAlign(RIGHT);
pushMatrix();
scale(0.5);
text(nf(airPoints,4) + "PTS", width*2-20, 40);
popMatrix();
}
if (winMode)
{
winscreen();
}
if((keyPressed) && (key == BACKSPACE))
{
drawMode = true;
playMode = false;
winMode = false;
introMode = false;
}
}
class Bike
{
float frontX, frontY;
float prevX, prevY;
float xSpeed, ySpeed;
float xAccel, yAccel;
float groundFront, groundBack, clear;
float backX;
float backY;
float angle1 = 0.0;
float dx, dy;
boolean airtime = false;
Bike(float ex, float why, float exSpeed, float whySpeed)
{
frontX = ex;
frontY = why;
xSpeed = exSpeed;
ySpeed = whySpeed;
xAccel = 0.0;
yAccel = 0.2;
backX = frontX-1;
backY = frontY+50;
airPoints = 0;
crash = false;
}
//////////////////// BEGIN CALCULATE ////////////////////
void calculate()
{
if((frontX < width+150-xSpeed-wheelRadius)&&(frontX > 1))
{
if((keyPressed) && (key == CODED))
{
if (keyCode == RIGHT)
xAccel = 0.1;
else if (keyCode == LEFT)
{
if (xSpeed <= 0)
{
xSpeed = 0;
xAccel = 0;
}
else
xAccel = -0.1;
}
}
else
xAccel = 0;
groundFront = (trackShape[int(frontX)]);
clear = trackShape[int(frontX+(wheelRadius/zoom))];
if((frontY < clear-ySpeed)&&(crash == false)) //if track in front is clear...
{
//and if ground is touched, then stop gravity, and accelerate
if(frontY >= groundFront-wheelRadius-1)
{
//Limit xSpeed to 3 pixels per frame
if(xSpeed > 2)
xSpeed = 2;
else
xSpeed += xAccel;
frontY = groundFront - wheelRadius + ySpeed+1;
ySpeed = (frontY - backY) * (xSpeed/20);
airtime = false;
}
else //else, if no ground, activate gravity
{
ySpeed += yAccel;
frontY += ySpeed;
airPoints ++;
airtime = true;
}
}
else // else (if crash)
{
crash = true;
xSpeed = 0;
xAccel = 0;
airPoints = 0;
if(frontY >= groundFront-wheelRadius)
{
frontY = groundFront-wheelRadius;
}
else //else, if no ground, activate gravity
{
ySpeed += yAccel;
frontY += ySpeed;
}
}
frontX += xSpeed;
}
dx = frontX - backX;
dy = frontY - backY;
angle1 = atan2(dy, dx);
if(!crash)
backX = frontX - (cos(angle1) * segLength);
else
backX = frontX - (cos(angle1) * segLength)+ySpeed;
if(backX > 0)
{
//And here are the two hardest lines ever
groundBack = (trackShape[int(backX + ( ((frontX - backX) /zoom)*(zoom-1)))]-(wheelRadius));
groundBack += ((groundBack+wheelRadius)-(frontY+wheelRadius-1))*(zoom);
}
else
groundBack = trackShape[0];
if (backY < groundBack)// if back wheel is above ground
{
if(airtime)
backY = frontY - (sin(angle1) * segLength);
else
backY = frontY - (sin(angle1) * segLength)+2;
}
else
backY = groundBack+1;
if(frontX > width)
{
winMode = true;
playMode = false;
}
}
//////////////////// END OF CALCULATE ////////////////////
void display(){
frontTire.drawMode(CORNER);
if (crash)
frontTire.draw(frontX-20, frontY-12);
else
{
frontTire.draw(frontX-10, frontY-12);
}
shape(backX, backY, angle1);
}
void shape(float segX, float segY, float segA) {
pushMatrix();
translate(segX, segY);
rotate(segA);
redBike.drawMode(CORNER);
redBike.draw(-15, -30);
popMatrix();
}
}
void drawTrack()
{
float drawY = mouseY;
float pdrawY = pmouseY;
float xSteps, ySteps;
float increment;
background(255);
if(mousePressed)
{
// Constrain mouseX positions to prevent array out of bounds
int drawX = constrain (mouseX, 0, width+15);
int pdrawX = constrain (pmouseX, 0, width+15);
if(drawX > pdrawX)
{
xSteps = drawX - pdrawX;
ySteps = drawY - pdrawY;
increment = (ySteps*1.0) / xSteps;
for(int i = pdrawX; i <= drawX; i++)
{
trackShape[i] = pdrawY;
pdrawY += increment;
}
}
}
//Display Current Draw Status
for(int i = 0; i < width-1; i++)
{
line (i, trackShape[i], (i+1), trackShape[i+1]);
}
if((keyPressed) && (key == ENTER))
{
drawMode = false;
playMode = true;
bb = new Bike(10, trackShape[10] -wheelRadius, 0, 0);
}
}
void winscreen()
{
int combination = int((trackShape[0]-bb.frontY)/10)+1;
fill(255, 25);
pushMatrix();
scale(0.5);
textAlign(LEFT);
text("Your score is:", 100, height/2-100);
text(airPoints + " air points", 100, height/2-50);
text( "X " + combination + " for climbing = ", 100, height/2);
text(airPoints * combination + " points!", 100, height/2 + 50);
popMatrix();
}