diff --git a/Performance/PixelPerfectCollision/Project.xml b/Performance/PixelPerfectCollision/Project.xml
index ddb1fcd3e..faa24f06b 100644
--- a/Performance/PixelPerfectCollision/Project.xml
+++ b/Performance/PixelPerfectCollision/Project.xml
@@ -16,7 +16,7 @@
-
+
diff --git a/Performance/PixelPerfectCollision/assets/alien.png b/Performance/PixelPerfectCollision/assets/alien.png
index 514d1d081..b0f2b9b38 100644
Binary files a/Performance/PixelPerfectCollision/assets/alien.png and b/Performance/PixelPerfectCollision/assets/alien.png differ
diff --git a/Performance/PixelPerfectCollision/source/Alien.hx b/Performance/PixelPerfectCollision/source/Alien.hx
new file mode 100644
index 000000000..0cab584dc
--- /dev/null
+++ b/Performance/PixelPerfectCollision/source/Alien.hx
@@ -0,0 +1,59 @@
+import flixel.FlxG;
+import flixel.FlxSprite;
+import flixel.tweens.FlxEase;
+import flixel.tweens.FlxTween;
+
+class Alien extends DemoSprite
+{
+ var collides:Bool = false;
+
+ public function new()
+ {
+ super();
+
+ // set dance dance interstellar animations
+ loadGraphic("assets/alien.png", true);
+ /*
+ * WebGL has trouble displaying large number of sprites with dynamic coloring,
+ * so we switch bewteen two similar animations with different colors.
+ */
+ var fps = FlxG.random.int(6, 10);
+ animation.add("dance_off", [0, 1, 0, 2], fps);
+ animation.add("dance_on", [3, 4, 3, 5], fps);
+ animation.play("dance_off"); // dance!
+ }
+
+ /**
+ * Randomize position, scrollFactor, velocity and alpha.
+ */
+ public function randomize()
+ {
+ var ran = FlxG.random;
+ x = ran.int(0, Std.int(FlxG.width - width)) + FlxG.camera.scroll.x;
+ y = ran.int(0, Std.int(FlxG.height - height)) + FlxG.camera.scroll.y;
+ alpha = ran.float(0.1, 1.0);
+ scrollFactor.x = alpha;
+ // negate the x-offset caused from scrollFactor
+ x += FlxG.camera.scroll.x * (scrollFactor.x - 1);
+ velocity.set(-ran.float(5, 25), 0);
+
+ // Neat tweening effect for new aliens appearing
+ var toY = y;
+ y = (y < FlxG.height / 2) ? -20 : FlxG.height + 20;
+ FlxTween.tween(this, {y: toY}, 1.0, { ease: FlxEase.expoOut, startDelay: ran.float() * 0.5 });
+ }
+
+ /**
+ * Switches the between the red/white color to show whether an overlap is occurring.
+ * @param value
+ */
+ override function setCollides(value:Bool)
+ {
+ if (value != collides)
+ {
+ collides = value;
+ var frame = animation.curAnim.curFrame;
+ animation.play("dance_" + (collides ? "on" : "off"), false, false, frame);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Performance/PixelPerfectCollision/source/DemoSprite.hx b/Performance/PixelPerfectCollision/source/DemoSprite.hx
new file mode 100644
index 000000000..b68d63325
--- /dev/null
+++ b/Performance/PixelPerfectCollision/source/DemoSprite.hx
@@ -0,0 +1,66 @@
+import flixel.FlxG;
+import flixel.FlxObject;
+import flixel.FlxSprite;
+import flixel.math.FlxRect;
+
+class DemoSprite extends FlxSprite
+{
+ public function new (x = 0.0, y = 0.0)
+ {
+ super(x, y);
+ }
+
+ /**
+ * Switches the between the red/white color to show whether an overlap is occurring.
+ */
+ public function setCollides(value:Bool)
+ {
+ color = value ? 0xFFac3232 : 0xFF6abe30;
+ }
+
+ public function resetAngle()
+ {
+ angle = 0;
+ angularVelocity = 0;
+ }
+
+ public function resetScale()
+ {
+ scale.set(1, 1);
+ }
+
+ public function randomAngle()
+ {
+ angle = FlxG.random.float() * 360;
+ angularVelocity = FlxG.random.float(50, 100);
+ }
+
+ public function randomScale()
+ {
+ scale.x = FlxG.random.float(0.5, 2.0);
+ scale.y = scale.x;
+ }
+
+ #if debug
+ override function draw()
+ {
+ // For debugging
+ // drawDebugScreenBounds();
+
+ super.draw();
+ }
+
+ function drawDebugScreenBounds()
+ {
+ for (camera in cameras)
+ {
+ var rect = getScreenBounds(camera);
+ var gfx = beginDrawDebug(camera);
+ // fill static graphics object with square shape
+ gfx.lineStyle(1, 0x0000ff, 0.5);
+ gfx.drawRect(rect.x, rect.y, rect.width, rect.height);
+ endDrawDebug(camera);
+ }
+ }
+ #end
+}
\ No newline at end of file
diff --git a/Performance/PixelPerfectCollision/source/PlayState.hx b/Performance/PixelPerfectCollision/source/PlayState.hx
index b48c5e4ca..2b2ab1d46 100644
--- a/Performance/PixelPerfectCollision/source/PlayState.hx
+++ b/Performance/PixelPerfectCollision/source/PlayState.hx
@@ -1,6 +1,5 @@
package;
-import flash.system.System;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.FlxState;
@@ -8,10 +7,12 @@ import flixel.text.FlxText;
import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import flixel.math.FlxPoint;
+import flixel.math.FlxVector;
import flixel.math.FlxAngle;
import flixel.util.FlxColor;
import flixel.util.FlxCollision;
import flixel.group.FlxGroup;
+import flash.system.System;
import openfl.display.FPS;
using flixel.util.FlxSpriteUtil;
@@ -25,14 +26,26 @@ class PlayState extends FlxState
// how many aliens are created initially
inline static var NUM_ALIENS:Int = 50;
- // How fast the player moves
- inline static var PLAYER_SPEED:Int = 75;
-
- inline static var INFO:String = "Collisions: |hits|\n" + "FPS: |fps| \n\n" + "[W/S] Objects: |objects|\n"
- + "[A/D] Alpha tolerance: |alpha|\n" + "[ARROWS] Move\n" + "[R] Randomize\n" + "[SPACE] Toggle rotations";
+ inline static var INFO_FULL:String
+ = "Collisions: |hits|\n"
+ #if debug + "Checks: |checks|\n" #end
+ + "FPS: |fps|\n\n"
+ + "[W/S] Objects: |objects|\n"
+ + "[A/D] Alpha tolerance: |alpha|\n"
+ + "[ARROWS] Move\n"
+ + "[R] Randomize\n"
+ + "[SPACE] |rotate| rotation\n"
+ + "[T] |scale| scale\n"
+ + "[H] Toggle instructions";
+
+ inline static var INFO_MIN:String
+ = "Objects: |objects|\n"
+ #if debug + "Checks: |checks|\n" #end
+ + "Collisions: |hits|\n"
+ + "FPS: |fps|";
// group holding the player and the aliens
- var aliens:FlxTypedGroup;
+ var aliens:FlxTypedGroup;
// the player ship
var player:Player;
@@ -40,6 +53,9 @@ class PlayState extends FlxState
// number of collisions at any given time
var numCollisions:Int = 0;
+ // number of collisions at any given time
+ var numChecks:Int = 0;
+
// setting this to 255 means two object will collide only if totally opaque
var alphaTolerance:Int = 1;
@@ -49,27 +65,40 @@ class PlayState extends FlxState
// to track fps
var fps:FPS;
- // wether the objects should rotate
- var rotate(default, set):Bool = true;
+ // whether the objects should rotate
+ var rotate:Bool = false;
+ // whether the objects should be scaled
+ var scale:Bool = false;
+ // whether the key instructions will show
+ var showFullInfo = true;
override public function create():Void
{
super.create();
+ FlxG.camera.bgColor = FlxG.stage.color;
// the group containing all the objects
- add(aliens = new FlxTypedGroup());
+ add(aliens = new FlxTypedGroup());
// create the player
add(player = new Player());
+ FlxG.camera.follow(player);
+ FlxG.camera.setScrollBounds(0, FlxG.width * 10, 0, FlxG.height);
+ FlxG.worldBounds.set(-10, -10, FlxG.camera.maxScrollX + 20, FlxG.camera.maxScrollY + 20);
+
+ updateSpriteAngles();
+ updateSpriteScales();
// add objects for more interstellar fun!
for (i in 1...NUM_ALIENS)
addAlien();
+
// add in some text so we know what's happening
- infoText = new FlxText(2, 0, 400, INFO);
+ infoText = new FlxText(2, 0, 400, INFO_FULL);
infoText.y = FlxG.height - infoText.height;
- infoText.setBorderStyle(OUTLINE);
+ infoText.setBorderStyle(OUTLINE, FlxColor.BLACK);
+ infoText.scrollFactor.x = 0;
add(infoText);
// just need this to get the fps, so we display it outside view range
@@ -77,9 +106,6 @@ class PlayState extends FlxState
// makes low fps less noticable
FlxG.fixedTimestep = false;
-
- // don't need the cursor
- FlxG.mouse.visible = false;
}
/**
@@ -87,35 +113,20 @@ class PlayState extends FlxState
*/
function addAlien():FlxSprite
{
- var alien = aliens.recycle(FlxSprite);
- alien.loadGraphic("assets/alien.png", true); // load graphics from asset
- alien.animation.add("dance", [0, 1, 0, 2], FlxG.random.int(6, 10)); // set dance dance interstellar animation
- alien.animation.play("dance"); // dance!
- randomize(alien); // set position, angle and alpha to random values
- return alien;
- }
-
- /**
- * Randomize position, angle and alpha of `obj`.
- */
- function randomize(obj:FlxSprite):FlxSprite
- {
- // The start position of the alien is offscreen on a circle
- var point = getRandomCirclePos();
- obj.setPosition(point.x, point.y);
- point.put(); // recycle point
-
- var destX = FlxG.random.int(0, Std.int(FlxG.width - obj.width));
- var destY = FlxG.random.int(0, Std.int(FlxG.height - obj.height));
- obj.alpha = FlxG.random.float(0.3, 1.0);
-
- // Neat tweening effect for new aliens appearing
- FlxTween.tween(obj, {x: destX, y: destY}, 2, {ease: FlxEase.expoOut});
-
+ var alien = aliens.recycle(Alien);
+ alien.randomize();
+
if (rotate)
- randomizeRotation(obj);
-
- return obj;
+ alien.randomAngle();
+ else
+ alien.resetAngle();
+
+ if (scale)
+ alien.randomScale();
+ else
+ alien.resetScale();
+
+ return alien;
}
/**
@@ -124,47 +135,33 @@ class PlayState extends FlxState
override public function update(elapsed:Float):Void
{
super.update(elapsed);
-
+
handleInput();
checkCollisions();
updateInfo();
-
- player.screenWrap(); // make sure the player can't go offscreen
}
function handleInput():Void
{
- // Reset velocity to (0,0)
- player.velocity.set();
-
- // player movement
- if (FlxG.keys.pressed.LEFT)
- player.velocity.x = -PLAYER_SPEED;
- if (FlxG.keys.pressed.RIGHT)
- player.velocity.x = PLAYER_SPEED;
- if (FlxG.keys.pressed.UP)
- player.velocity.y = -PLAYER_SPEED;
- if (FlxG.keys.pressed.DOWN)
- player.velocity.y = PLAYER_SPEED;
-
// toggle rotation
if (FlxG.keys.justReleased.SPACE)
{
rotate = !rotate;
- rotate ? randomizeRotation(player) : resetRotation(player);
+ updateSpriteAngles();
+ }
+
+ // toggle scale
+ if (FlxG.keys.justReleased.T)
+ {
+ scale = !scale;
+ updateSpriteScales();
}
// randomize
if (FlxG.keys.justReleased.R)
{
- for (obj in aliens)
- {
- // Don't randomize the player's position
- if (obj != player)
- {
- randomize(obj);
- }
- }
+ for (a in aliens)
+ a.randomize();
}
// increment/decrement number of objects
@@ -173,6 +170,7 @@ class PlayState extends FlxState
for (i in 0...3)
addAlien();
}
+
if (FlxG.keys.justReleased.S)
{
for (i in 0...3)
@@ -182,6 +180,13 @@ class PlayState extends FlxState
alien.kill();
}
}
+
+ if (FlxG.keys.justReleased.H)
+ {
+ showFullInfo = !showFullInfo;
+ updateInfo();
+ infoText.y = FlxG.height - infoText.height;
+ }
// increment/decrement alpha tolerance
if (FlxG.keys.pressed.D)
@@ -205,105 +210,94 @@ class PlayState extends FlxState
*/
function checkCollisions():Void
{
+ numChecks = 0;
numCollisions = 0;
- player.color = FlxColor.GREEN;
+ player.color = 0xFF6abe30;
- for (i in 0...aliens.length)
+ for (alien in aliens)
+ alien.cameraWrap(WALL);
+
+ for (alien1 in aliens)
{
- var obj1 = aliens.members[i];
var collides = false;
// Only collide alive members
- if (!obj1.alive)
+ if (!alien1.alive)
continue;
-
- for (j in 0...aliens.length)
- {
- var obj2 = aliens.members[j];
-
- // Only collide alive members and don't collide an object with itself
- if (!obj2.alive || (i == j))
- continue;
-
- // this is how we check if obj1 and obj2 are colliding
- if (FlxCollision.pixelPerfectCheck(obj1, obj2, alphaTolerance))
- {
- collides = true;
- numCollisions++;
- break;
- }
- }
-
+
+ numChecks++;
// We check collisions with the player seperately, since he's not in the group
- if (FlxCollision.pixelPerfectCheck(obj1, player, alphaTolerance))
+ if (FlxCollision.pixelPerfectCheck(alien1, player, alphaTolerance))
{
collides = true;
numCollisions++;
- player.color = FlxColor.RED;
+ player.color = 0xFFac3232;
}
-
- obj1.color = collides ? FlxColor.RED : FlxColor.WHITE;
+ else
+ {
+ for (alien2 in aliens)
+ {
+ // Only collide alive members and don't collide an object with itself
+ if (!alien2.alive || alien1 == alien2)
+ continue;
+
+ numChecks++;
+ // this is how we check if obj1 and obj2 are colliding
+ if (FlxCollision.pixelPerfectCheck(alien1, alien2, alphaTolerance))
+ {
+ collides = true;
+ numCollisions++;
+ break;
+ }
+ }
+ }
+
+ alien1.setCollides(collides);
}
}
-
- function updateInfo():Void
- {
- infoText.text = INFO // + 1 for the player that is not in the group
- .replace("|objects|", Std.string(aliens.countLiving() + 1))
- .replace("|alpha|", Std.string(alphaTolerance))
- .replace("|hits|", Std.string(numCollisions))
- .replace("|fps|", Std.string(fps.currentFPS));
- }
-
- function set_rotate(Value:Bool):Bool
+
+ function updateSpriteAngles()
{
- if (Value)
- aliens.forEach(randomizeRotation);
+ if (rotate)
+ {
+ for (alien in aliens)
+ alien.randomAngle();
+
+ player.randomAngle();
+ }
else
- aliens.forEach(resetRotation);
-
- return rotate = Value;
- }
-
- function randomizeRotation(obj:FlxSprite):Void
- {
- obj.angle = FlxG.random.float() * 360;
- obj.angularVelocity = 100;
- }
-
- function resetRotation(obj:FlxSprite):Void
- {
- obj.angle = 0;
- obj.angularVelocity = 0;
+ {
+ for (alien in aliens)
+ alien.resetAngle();
+
+ player.resetAngle();
+ }
}
-
- /**
- * Returns a random position on an offscreen circle to tween the aliens from / to
- */
- function getRandomCirclePos():FlxPoint
+
+ function updateSpriteScales()
{
- // choose a random position on our circle, from 1° to 360°
- var startAngle = FlxG.random.int(1, 360);
-
- // make sure the radius of our circle is 200 px bigger than the game's width / height (whichever is bigger)
- var startRadius = (FlxG.width > FlxG.height) ? (FlxG.height + 200) : (FlxG.width + 200);
-
- var coords:FlxPoint = FlxAngle.getCartesianCoords(startRadius, startAngle);
- // Currently, the coords represent a circle with its center at (0,0) - let's move them!
- coords.x += FlxG.width / 2;
- coords.y += FlxG.height / 2;
-
- return coords;
+ if (scale)
+ {
+ for (alien in aliens)
+ alien.randomScale();
+ }
+ else
+ {
+ for (alien in aliens)
+ alien.resetScale();
+ }
}
-}
-class Player extends FlxSprite
-{
- public function new()
+ function updateInfo():Void
{
- super();
- loadGraphic("assets/ship.png");
- screenCenter();
- angularVelocity = 50;
+ infoText.text = (showFullInfo ? INFO_FULL : INFO_MIN)
+ .replace("|checks|", Std.string(numChecks))
+ .replace("|hits|", Std.string(numCollisions))
+ .replace("|fps|", Std.string(fps.currentFPS))
+ .replace("|objects|", Std.string(aliens.countLiving() + 1))// + 1 for the player
+ .replace("|alpha|", Std.string(alphaTolerance))
+ .replace("|rotate|", rotate ? "Disable" : "Enable")
+ .replace("|scale|", scale ? "Disable" : "Enable");
+
}
}
diff --git a/Performance/PixelPerfectCollision/source/Player.hx b/Performance/PixelPerfectCollision/source/Player.hx
new file mode 100644
index 000000000..c3323358d
--- /dev/null
+++ b/Performance/PixelPerfectCollision/source/Player.hx
@@ -0,0 +1,33 @@
+import flixel.FlxG;
+import flixel.FlxSprite;
+
+class Player extends DemoSprite
+{
+ // How fast the player moves
+ inline static var PLAYER_SPEED:Int = 75;
+
+ public function new()
+ {
+ super();
+ loadGraphic("assets/ship.png");
+ screenCenter();
+ x += FlxG.width;
+ }
+
+ override function update(elapsed:Float)
+ {
+ super.update(elapsed);
+
+ // player movement
+ velocity.set(0, 0);
+
+ if (FlxG.keys.pressed.LEFT)
+ velocity.x = -PLAYER_SPEED;
+ if (FlxG.keys.pressed.RIGHT)
+ velocity.x = PLAYER_SPEED;
+ if (FlxG.keys.pressed.UP)
+ velocity.y = -PLAYER_SPEED;
+ if (FlxG.keys.pressed.DOWN)
+ velocity.y = PLAYER_SPEED;
+ }
+}
\ No newline at end of file