Some (productive?) hours of boredom.
[size=6]Version 2[/size]
Draw with your mouse, this will become the track.
Make sure to start off going downwards or gravity can’t take effect on your cart!
[center][size=4]Play[/size][/center]
import flash.geom.Point;
Stage.scaleMode = "noScale";
Stage.align = "TL";
Stage.showMenu = false;
var track:MovieClip;
var section:MovieClip;
var length:Number = 60;
var ball;
var friction = 0.9999;
var gravity = 0.5;
var points:Array;
var p:Point;
var drawing:Boolean = false;
var lines:Array;
function onMouseDown() {
points = [];
lines = [];
drawing = true;
track.clear();
_root.clear();
if (ball) ball.removeMovieClip();
section = _root.createEmptyMovieClip("_section", 2);
section._x = _xmouse;
section._y = _ymouse;
section.onMouseMove = function() {
this.clear();
this.lineStyle(1, 0x666666);
this.lineTo(this._xmouse, this._ymouse);
updateAfterEvent();
}
section.onMouseMove();
p = new Point(_xmouse, _ymouse);
points.push(p);
_root.lineStyle(1, 0xCCCCCC);
_root.moveTo(0, _ymouse);
_root.lineTo(2000, _ymouse);
_root.moveTo(_xmouse, _ymouse);
}
function onMouseUp() {
points.push(new Point(_xmouse, _ymouse));
_root.lineTo(_xmouse, _ymouse);
drawing = false;
section.removeMovieClip();
if (!track) {
track = _root.createEmptyMovieClip("_track", 1);
}
var p1:Point, p2:Point, p3:Point, mid1:Point, mid2:Point;
var p1:Point = linearBezierPoint([points[0], points[1]], 0.5);
track.lineStyle(0, 0x000000);
track.moveTo(points[0].x, points[0].y);
track.lineTo(p1.x, p1.y);
lines.push({x: points[0].x, y: points[0].y});
for (var i:Number=0; i<points.length-2; i++) {
p1 = points*;
p2 = points[i+1];
p3 = points[i+2];
mid1 = linearBezierPoint([p1, p2], 0.5);
mid2 = linearBezierPoint([p2, p3], 0.5);
lines = lines.concat(track.bezier([mid1, p2, mid2], 20));
}
lines.push({x: p3.x, y: p3.y});
track.lineTo(p3.x, p3.y);
for (i=0; i<lines.length; i++) {
var a = lines*;
var b = lines[i+1];
a.dx = b.x - a.x;
a.dy = b.y - a.y;
a.a = Math.atan2(a.dy, a.dx);
}
lines.pop();
ball = track.attachMovie("ball", "_ball", 1);
ball._x = lines[0].x;
ball._y = lines[0].y;
ball._rotation = 180*lines[0].a/Math.PI;
ball.v = 0;
ball.line = 0;
_root.onEnterFrame = function() {
var l = lines[ball.line];
ball.v += Math.sin(l.a)*gravity;
ball.v *= friction;
run(ball.v);
ball._rotation = 180/Math.PI*lines[ball.line].a;
};
}
function onMouseMove() {
if (!drawing) return;
var dx:Number = _xmouse - p.x;
var dy:Number = _ymouse - p.y;
var d:Number = Math.sqrt(dx*dx+dy*dy);
if (d >= length) {
var a:Number = Math.atan2(dy, dx);
p = new Point(p.x+length*Math.cos(a), p.y+length*Math.sin(a));
points.push(p);
section._x = p.x;
section._y = p.y;
section.onMouseMove();
_root.lineTo(p.x, p.y);
onMouseMove();
}
}
function run(distance) {
var l = lines[ball.line];
if (ball.v == 0) return;
var ex:Number = l.x, ey:Number = l.y;
if (ball.v >= 0) {
ex += l.dx;
ey += l.dy;
}
var dx:Number = ex - ball._x, dy:Number = ey - ball._y;
var d:Number = Math.sqrt(dx*dx + dy*dy);
if (d < Math.abs(distance)) {
ball._x = ex;
ball._y = ey;
ball.line += ball.v > 0 ? 1 : -1;
if (ball.line == -1 || ball.line == lines.length) {
ball.line -= ball.v > 0 ? 1 : -1;
ball.v *= -0.3;
} else {
run((Math.abs(distance) - d)*Math.abs(distance)/distance);
}
} else {
ball._x += distance*Math.cos(l.a);
ball._y += distance*Math.sin(l.a);
}
}
MovieClip.prototype.linearBezierPoint = function(p:Array, t:Number):Point {
if (t < 0 || t > 1 || p.length != 2) return null;
return new Point(
p[0].x+(p[1].x-p[0].x)*t,
p[0].y+(p[1].y-p[0].y)*t
);
};
MovieClip.prototype.quadraticBezierPoint = function(p:Array, t:Number):Point {
if (t < 0 || t > 1 || p.length != 3) return null;
var ax:Number, bx:Number;
bx = 2*(p[1].x-p[0].x);
ax = p[2].x - p[0].x - bx;
var ay:Number, by:Number;
by = 2*(p[1].y - p[0].y);
ay = p[2].y - p[0].y - by;
var t2:Number = t*t;
return new Point(
ax*t2 + bx*t + p[0].x,
ay*t2 + by*t + p[0].y
);
};
MovieClip.prototype.bezier = function (p:Array, segments:Number):Array {
if (segments < 1) return;
var func:Function;
if (p.length < 2) {
return;
} else if (p.length == 2) {
func = this.linearBezierPoint;
} else if (p.length == 3) {
func = this.quadraticBezierPoint;
} else if (p.length == 4) {
func = this.cubicBezierPoint;
} else {
return;
}
var pr:Array = [];
var dt:Number = 1/segments;
var s:Point = func(p, 0);
this.moveTo(s.x, s.y);
for (var i:Number=1; i<=segments; i++) {
s = func(p, i*dt);
pr.push({x: s.x, y: s.y});
this.lineTo(s.x, s.y);
}
return pr;
}
[size=6]Version 1[/size]
Draw with your mouse, this will become the track.
You can create sections of track that will boost your cart.
Holding one of the following keys will create boost sections:
Up: Boost no matter of the direction of your cart
Left: Boost when the cart is moving backwards
Right: Boost when the cart is moving forwards
[center][size=4]Play[/size][/center]
Stage.scaleMode = "noScale";
Stage.align = "TL";
// The previous position of the mouse whilst drawing
var m:Object = {
x: 0,
y: 0
};
var friction:Number = 1; //0.999; // Friction whilst not being boosted
var gravity:Number = 0.5; // Gravitational force in effect whilst not being boosted
var boost:Number = 0.1; // Acceleration whilst being boosted
var ball:MovieClip; // Actually the rollercoaster's cart
var lines:Array = []; // The track
var drawing:Boolean = false;// Not drawing
/********************
* CREATELINE
* Creates the track in the `lines` array as the user draws
*******************/
function createLine(dx, dy) {
// The line object
var line:Object = {
x: m.x, /* Starting X of the line */
y: m.y, /* Starting Y of the line */
dx: dx, /* Change in X over course of line */
dy: dy, /* Change in Y over course of line */
a: Math.atan2(dy, dx), /* Angle of line */
boostB: Key.isDown(Key.UP), /* Boost in both directions */
boostL: Key.isDown(Key.LEFT), /* Boost when going left */
boostR: Key.isDown(Key.RIGHT) /* Boost when going right */
};
// Select which colour to draw in
var color:Number = 0;
if (line.boostB) {
color = 0xFF0000;
} else if (line.boostL) {
color = 0x00FF00;
} else if (line.boostR) {
color = 0x0000FF;
}
// Update the previous mouse position variable
m.x += dx;
m.y += dy;
// Draw the line
lines.push(line);
track.lineStyle(1, color);
track.lineTo(line.x+line.dx, line.y+line.dy);
}
function onMouseDown() {
// If we're drawing for a second time then `track` will exist;
// in which case we want to reset everything
if (track) {
track.removeMovieClip();
delete onEnterFrame;
lines = [];
}
// Set off the drawing
drawing = true;
m.x = _xmouse;
m.y = _ymouse;
// Set up our track
_root.createEmptyMovieClip("track", 1);
track.lineStyle(1, 0xCCCCCC);
track.moveTo(0, _ymouse);
track.lineTo(2000, _ymouse);
track.moveTo(m.x, m.y);
}
function onMouseUp() {
// No longer drawing, finish the last line
drawing = false;
createLine(_xmouse - m.x, _ymouse - m.y);
// Create the cart
ball = track.attachMovie("ball", "ball", 1);
ball._x = lines[0].x;
ball._y = lines[0].y;
ball.v = 0.2;
ball.line = 0;
// Set the main loop
_root.onEnterFrame = function() {
// How the cart should react to it's environment:
// BoostB [Boost in both directions]
// BoostL [Boost when going left]
// BoostR [Boost when going right]
// Otherwise [Apply gravity and friction]
var l = lines[ball.line];
if (l.boostB) {
ball.v += boost*Math.abs(ball.v)/ball.v;
} else if (l.boostL && ball.v <= 0) {
ball.v -= boost;
} else if (l.boostR && ball.v >= 0) {
ball.v += boost;
} else {
ball.v += Math.sin(l.a)*gravity;
ball.v *= friction;
}
// Run the line processing for the cart then update rotation
run(ball.v);
ball._rotation = 180/Math.PI*lines[ball.line].a;
};
}
function onMouseMove() {
if (!drawing) return;
// distance moved
var dx:Number = _xmouse - m.x, dy:Number = _ymouse - m.y;
var d:Number = Math.sqrt(dx*dx + dy*dy);
// Keep the lines less than 10 units long
// (I can't remember why I put it in, but I'm going to leave it.)
if (d >= 10) {
var a = Math.atan2(dy, dx);
dx = 10*Math.cos(a);
dy = 10*Math.sin(a);
createLine(dx, dy);
onMouseMove();
} else {
createLine(_xmouse-m.x, _ymouse-m.y);
}
}
function run(distance) {
// The line the ball is on.
var l = lines[ball.line];
// If the ball is not moving then don't both continuing (unlikely)
if (ball.v == 0) return;
// Calculate the coordinates of the end the cart is heading to on it's current line
var ex:Number = l.x, ey:Number = l.y;
if (ball.v >= 0) {
ex += l.dx;
ey += l.dy;
}
// Distace to the calculated end
var dx:Number = ex - ball._x, dy:Number = ey - ball._y;
var d:Number = Math.sqrt(dx*dx + dy*dy);
// If we get to the end of the line before we have travelled the desired distance then we need to move onto the next line
if (d < Math.abs(distance)) {
// Move to the end of the line
ball._x = ex;
ball._y = ey;
// Move onto the next line
ball.line += ball.v > 0 ? 1 : -1;
// If we've reached either end of the track
if (ball.line == -1 || ball.line == lines.length) {
// Rebound
ball.line -= ball.v > 0 ? 1 : -1;
ball.v *= -0.3;
// Otherwise
} else {
// Run again on the next line with the distance we have to travel minus the distance we just travelled
run((Math.abs(distance) - d)*Math.abs(distance)/distance);
}
// Or if we can move the desired distance on our current line
} else {
// Do so
ball._x += distance*Math.cos(l.a);
ball._y += distance*Math.sin(l.a);
}
}
Hope you enjoy :thumb:
[size=1]Oh, 2.9k posts[/size]