Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - Ohmnivore

Pages: [1]
1
games / Global game jam game made in 48 hours
« on: Mon, Jan 27, 2014 »
I absolutely loved the entire jamming experience, and here's what we made using Flixel: http://globalgamejam.org/2014/games/no-i-team

2
help / MarkupText class - marking up dat FlxText!
« on: Thu, Dec 26, 2013 »
In my short albeit awesome existence I've wished many a time that FlxText could be marked up, that is allowed to have its text's color and/or size to be changed at some places, while retaining another format for the rest. Then I decided to venture into the source code and roll my own FlxText with blackjack, strippers, and markup. It's definitely more fun to read pimped up text than to read that monotonous Nokia font. It also includes a markup exporter/importer (because I had to send it around through the interwebs, and I love minimizing bandwidth - that's why).

Merry Christmas and happy birthday to my homie Jesus!

Here be MarkupText, the core.
Code: [Select]
package
{
import flash.display.BitmapData;
import flash.text.TextField;
import flash.text.TextFormat;
import org.flixel.FlxText;
import org.flixel.FlxG;

/**
* Extends FlxText to allow marking up the text
* (changing size and/or color of parts of the text)
* Seems to also support multi-line/word-wrap.
* If text is a one-liner, set Autowidth to true.
* Else, set Autowidth to FALSE!!!
*
* @author Ohmnivore
*/
public class MarkupText extends FlxText
{
public var autowidth:Boolean;
public var markups:Array;

/**
* Creates a new <code>MarkupText</code> object at the specified position.
*
* @param X The X position of the text.
* @param Y The Y position of the text.
* @param Width The width of the text object (height is determined automatically).
* @param Text The actual text you would like to display initially.
* @param EmbeddedFont Whether this text field uses embedded fonts or nto
* @param Autowidth Wether this text field has its width set automatically (FOR ONE-LINERS ONLY)
* @param Markups Array of markup objects, or an empty array if you wish.
*/
public function MarkupText(X:Number, Y:Number, Width:uint, Text:String=null, EmbeddedFont:Boolean=true, Autowidth:Boolean = false, Markups:Array = null)
{
super(X, Y, Width, Text, EmbeddedFont);

autowidth = Autowidth;

if (autowidth)
{
_textField.multiline = false;
_textField.wordWrap = false;
}

_regen = true;
calcFrame();

markups = [];

if (Markups != null)
{
for each (var mark in Markups)
{
Markitup(mark);
}
}
}

public function Markitup(mark:Markup):void
{
markups.push(mark);
_textField.setTextFormat(new TextFormat("system", mark.size, mark.color),
mark.startindex, mark.endindex);
_regen = true;
calcFrame();
}

/**
* Returns a JSONed AS3 array of this instance's markups
*/
public function ExportMarkups():String
{
var arr:Array = [];

for each (var m:Markup in markups)
{
var arrm:Array = [];

arrm.push(m.startindex, m.endindex, m.size, m.color);

arr.push(arrm);
}

if (arr.length > 0) return JSON.stringify(arr);
else return "[]";
}

/**
* Markups the text using the passed exported string
*/
public function ImportMarkups(jsonedmarkups:String):void
{
if (jsonedmarkups.length > 2)
{
var arr:Array = JSON.parse(jsonedmarkups) as Array;

for each (var m:Array in arr)
{
Markitup(new Markup(m[0], m[1], m[2], m[3]));
}
}
}

/**
* Internal function to update the current animation frame.
*/
override protected function calcFrame():void
{
if(_regen)
{
//Need to generate a new buffer to store the text graphic
var i:uint = 0;
var nl:uint = _textField.numLines;
//trace(_textField.numLines);
height = 0;
if (autowidth) width = _textField.textWidth+2;
while(i < nl)
height += _textField.getLineMetrics(i++).height;
height += 4; //account for 2px gutter on top and bottom
_pixels = new BitmapData(width,height,true,0);
frameHeight = height;
if (autowidth) frameWidth = width;
_textField.height = height*1.2;
_flashRect.x = 0;
_flashRect.y = 0;
_flashRect.width = width;
_flashRect.height = height;
_regen = false;
}
else //Else just clear the old buffer before redrawing the text
_pixels.fillRect(_flashRect,0);

if((_textField != null) && (_textField.text != null) && (_textField.text.length > 0))
{
//Now that we've cleared a buffer, we need to actually render the text to it
var format:TextFormat = _textField.defaultTextFormat;
var formatAdjusted:TextFormat = format;
_matrix.identity();
//If it's a single, centered line of text, we center it ourselves so it doesn't blur to hell
if((format.align == "center") && (_textField.numLines == 1))
{
formatAdjusted = new TextFormat(format.font,format.size,format.color,null,null,null,null,null,"left");
if (!autowidth) _textField.setTextFormat(formatAdjusted);
_matrix.translate(Math.floor((width - _textField.getLineMetrics(0).width)/2),0);
}
//Render a single pixel shadow beneath the text
if(_shadow > 0)
{
_textField.setTextFormat(new TextFormat(formatAdjusted.font,formatAdjusted.size,_shadow,null,null,null,null,null,formatAdjusted.align));
_matrix.translate(1,1);
_pixels.draw(_textField,_matrix,_colorTransform);
_matrix.translate(-1,-1);
if (!autowidth) _textField.setTextFormat(new TextFormat(formatAdjusted.font,formatAdjusted.size,formatAdjusted.color,null,null,null,null,null,formatAdjusted.align));
}
//Actually draw the text onto the buffer
_pixels.draw(_textField,_matrix,_colorTransform);
if (!autowidth) _textField.setTextFormat(new TextFormat(format.font,format.size,format.color,null,null,null,null,null,format.align));
}

//Finally, update the visible pixels
if((framePixels == null) || (framePixels.width != _pixels.width) || (framePixels.height != _pixels.height))
framePixels = new BitmapData(_pixels.width,_pixels.height,true,0);
framePixels.copyPixels(_pixels, _flashRect, _flashPointZero);

//if (autowidth) width = _textField.textWidth;
}
}
}

Here be Markup, not the core, but still part of the family.
Code: [Select]
package 
{
public class Markup
{
public var size:uint = 9;
public var color:uint = 0xffffffff;
public var startindex:int;
public var endindex:int;

/**
* Object to be passed to MarkupText's constructor/Markitup function
*
* @param Startindex Zero-based, specifies first included character.
* @param Endindex First character after the markup, also zero-based.
* @param Size The size. Default is the flixel default (8).
* @param Color Markup color. Duh. Default is white like Tide!
*/
public function Markup(Startindex:int, Endindex:int, Size:uint = 8, Color:uint = 0xffffffff)
{
startindex = Startindex;
endindex = Endindex;
size = Size;
color = Color;
}

}
}

Hopefully, here be no bugs.

Errrm - Bugfix 1: Fixed exporting.
-Bugfix 2: Added more tolerance for importing and exporting (such as importing an empty array of markups), and added 2pixels when width is being calculated because otherwise the text would be cut off in the image. It's a weird bug, and a weird fix. Somehow 2 pixels is the perfect value.

3
help / [SOLVED]Explosion knock back?
« on: Sun, Dec 8, 2013 »
I'm a bit stumped on this one. My game has rockets and all, and it's almost essential that i implement knock back from rocket explosions. Knock back will only affect players. I tried setting the player's sprite's velocity, but since the arrow keys directly set the player's acceleration in my update loop, the knock back's effects stop after a frame. I'm wondering how i can achieve mario-style walking while still being able to apply force impulses on the player.

OK, so the way I implemented what I needed is actually dead simple. Instead of setting acceleration values, I increment/decrement velocity.x. The other important step is to carefully pick drag.x. This way it's possible to apply both impulses (through velocity) and forces (through acceleration).
P.S.: Now i can do rocket jumping!

4
releases / Streamy - Networking package for AIR
« on: Fri, Nov 22, 2013 »
Well here's the product of two days of hard work, figuring out the obscure flash socket stuff and ditching python along the way.
Streamy. So what's Streamy? It's a package for online multiplayer networking. I'll be straight: it only works with AIR, although that already is cool because it can run on mobile platforms. It's a package that basically uses both UDP and TCP. One for the quick updates, like sending player positions, and the other for important stuff you can't afford to lose, like a chat message.

It was greatly inspired from this: https://bitbucket.org/reidyd/legume

I have a sort of hello world set up here: https://github.com/Ohmnivore/StreamyTest

It's pretty much done. At least it fills my needs. If there's any feature you want to suggest, go ahead.

Edit - I'm considering of making a TCP-only version of Streamy. So the poor players on their browsers will be able to connect too.

5
help / [SOLVED]Walljump/Ledge grab problem
« on: Wed, Nov 20, 2013 »
I've been trying to implement wall jumping and ledge grabbing recently, and it's been a huge pain in the butt. I understand the concept well, it just doesn't work. After so much trying I don't even think I can think clearly, but here's what I do and what seems to be the problem.

I followed pretty much this tutorial here: http://bullettimeninja.blogspot.ca/2011/10/wall-kicking.html
Basicaly the idea is that while your player's sprite will collide but once, a "shadow" collision sprite that follows your player around and that's offset to the left/right depending on the facing will collide continuously. But in the code the shadow too is collided with the collision map, so what's the difference? Of course when I implement this method it does what I thought it would do: the player sticks to the wall for a frame, then falls.

So, I modified FlxG.collide a bit to override the FlxObject.separateX and FlxObject.separateY methods and take away the parts that modify the collided objects' positions. Then in my update loop I collide the shadow with the collision map, using the modified FlxG.collide. Then I check shadow.isTouching(ANY). If it returns false, then I determine that walljump/ledge grab is over, and return acceleration.y to normal. However this too triggers right after a frame, and doesn't do continuous collision like I'd like it to.

All in all, I think I need a function to see whether the shadow is touching anything at all, but without moving. Basically I need an overlap function that can work with a tilemap.

SOLUTION
FlxG.overlaps() treats the tilemap as a huge sprite, with anything within its bounds returning true. Instead, i figured out i had to use FlxTilemap.overlaps(). Duh. Doh.

6
help / [Tutorial]Dynamic vision system
« on: Wed, Nov 13, 2013 »
I just wrote a tutorial which you can find here: http://ohmnivore.elementfx.com/216/flixel-vision-system-part-1/#.UoQwYfmPSSo
But since I don't want to come across as a link spammer I have carefully converted it to the following post. I hope it will help other people so they won't need to start from point zero like I had to.

While working on my kick-ass stealth-tactical platformer game (built on Flixel and its supa cool power tools), I came across the need for a limited vision system. In other words, enemies need to have a limited vision cone. I also needed a very fast method that could support the multitude of enemies in a platformer. Because games are worth a thousand words, hereís a demo of the final vision system.
<a href="http://ohmnivore.elementfx.com/wp-content/uploads/2013/11/Z211.swf" target="_blank" rel="noopener noreferrer" class="bbc_link bbc_flash_disabled new_win">http://ohmnivore.elementfx.com/wp-content/uploads/2013/11/Z211.swf</a>
Sweet eh? Okay, now letís get to business. First off, the vision cone can be modeled into 3 parts: The circle, the upper delimiting line and the lower defining line.

For the sake of your own sanity letís assume the view origins from a single point, and not two distinct eyes. It still looks good anyways. The last assumption is that the player is a circle. Youíll understand later why. But for now, try to fit your character into a circle and mark its radius.

Not so bad, right? The characterís sprite is 24*24 pixels. If there are any imprecisions theyíre pretty much off by a pixel or two, so donít obsess over it. What we need is cheap, fast vision checking.

Back to circles. Circles are awesome. Circle-circle collision is like the best thing ever. All you need to do is check if the distance between both centers is smaller than the sum of both radiuses.

Okay, now let me outline the general steps for checking collision between the vision cone and the playerís circle.

1) Check if both circles collide. Circle-circle collision.

2) Check if the playerís circleís center is between the two delimiting lines.

3) Check if the playerís circleís centerís distance to either one of the lines is smaller than the playerís circleís radius. In short, circle-line collision.

4) Check if the line from the observerís eye towards the player collides with the tilemap, in which case the view is obstructed.

The player is visible if 1,4, and 2 or 3 return true.

Take note that these steps go from least computationally expensive to most expensive, this is plain common sense.

So hereís the class I used for the game. It also handles drawing! However I write code like crap when Iím in a hurry, so itís not neat. It does need a bit of adjustment for use in another game, but most stuff to change should be picked up by the compiler should you try to adapt it. If there is a demand for an in-depth explanation of the 4 vision system steps, Iíll try to expand on this tutorial as much as I can. Also I pretty much omitted the drawing part which is crucial after all. Cheers!
Code: [Select]
package 
{
import flash.display.Sprite;
import flash.geom.Point;
import org.flixel.FlxPoint;
import org.flixel.FlxSprite;
import org.flixel.FlxTilemap;
import flash.display.Shape;
import flash.display.BitmapData;
import flash.display.Bitmap;

public class Vision extends FlxSprite
{

public var state:Level;
public var radius:Number;
public var fov:Number;
public var zangle:Number;
public var parent;
public var xoffset:Number;
public var yoffset:Number;
public var view:Sprite;
public var vheight:int;
public var deg_to_rad:Number = 0.0174532925;

public function Vision(State:Level, Radius:Number, FOV:Number, Angle:Number, Parent, Xoffset:int, Yoffset:int)
{
state = State;
radius = Radius;
fov = FOV;
zangle = Angle;
parent = Parent;
x = parent.x;
y = parent.y;
xoffset = Xoffset;
yoffset = Yoffset;

view = new Sprite();
vheight = int(Math.tan(fov / 2 * deg_to_rad) * radius) * 2;
//trace("vheight", vheight);
view.graphics.lineStyle(1, 0xff910000);
view.graphics.beginFill(0xFF0000,0.35);
var finishp:Point = draw_arc(view, parent.width/2, vheight/2, parent.visionlength, -fov/2, fov/2, 1);
view.graphics.lineTo(parent.width/2, vheight/2);
view.graphics.lineTo(finishp.x, finishp.y);

height = vheight;
width =  parent.visionlength*1.5;


var b:BitmapData = new BitmapData( parent.visionlength*1.5, vheight, true, 0x00000000);
b.draw(view,null,null,null,null,true);
pixels = b;
state.views.add(this);
origin = new FlxPoint(xoffset, vheight / 2);

//fov += 90;
}

override public function update():void
{
var parentradius:Number = parent.visionlength * parent.vision;
if (parentradius != radius)
{
scale = new FlxPoint(parentradius/radius,parentradius/radius);
radius = parent.visionlength * parent.vision;
}
x = parent.x;
y = parent.y - vheight/2 + yoffset;
}

public function draw_arc(movieclip,center_x,center_y,radius,angle_from,angle_to,precision):Point {
            var angle_diff = angle_to - angle_from;
var deg_to_rad=0.0174532925;
            var steps=Math.round(angle_diff*precision);
            var angle=angle_from;
            var px=center_x+radius*Math.cos(angle*deg_to_rad);
            var py = center_y + radius * Math.sin(angle * deg_to_rad);
var initp;
//movieclip.graphics.lineTo(center_x, center_y);
            movieclip.graphics.moveTo(px, py);
            for (var i:int = 1; i <= steps; i++) {
                angle=angle_from+angle_diff/steps*i;
                movieclip.graphics.lineTo(center_x + radius * Math.cos(angle * deg_to_rad), center_y + radius * Math.sin(angle * deg_to_rad));
if (i == 1) initp = new Point(center_x + radius * Math.cos(angle * deg_to_rad), center_y + radius * Math.sin(angle * deg_to_rad));
            }
return initp;
}

public function checkIfSee():Boolean
{
if (checkCircle())
{
var deg_to_rad=0.0174532925;
var playerpos:FlxPoint = state.player.getMidpoint();
var relativep:FlxPoint = new FlxPoint((playerpos.x - (x)), (playerpos.y - (y + vheight/2)));
var theta:Number = (zangle) * deg_to_rad;
var rotatedp:Point = new Point(0,0);
rotatedp.x = Math.cos(theta) * relativep.x - Math.sin(theta) * relativep.y;
rotatedp.y = Math.sin(theta) * relativep.x + Math.cos(theta) * relativep.y;

if (inBetween(rotatedp))
{
if (checkRay()) return true;
}

if (touchingSight(rotatedp))
{
if (checkRay()) return true;
}
}

return false;
}

public function checkRay():Boolean
{
var playerpos:FlxPoint = state.player.getMidpoint();
if (state.collidemap.ray(new FlxPoint(x, y + vheight/2), new FlxPoint(playerpos.x, playerpos.y), null, 1)) return true;
else return false;
}

public function checkCircle():Boolean
{
var playerpos:FlxPoint = state.player.getMidpoint();
var eyepos:FlxPoint = new FlxPoint(x + xoffset, y + yoffset);
if (PtoPdist2(eyepos, playerpos) < (state.player.RADIUS + radius)*(state.player.RADIUS + radius))
{
//trace("Alert!");
return true;
}
else
{
return false;
}
}

static public function PtoPdist2(p1:FlxPoint, p2:FlxPoint):Number
{
return ((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
}

public function inBetween(rotatedp:Point):Boolean
{
if ((rotatedp.y < Math.tan(fov * deg_to_rad / 2) * rotatedp.x) && (rotatedp.y > -1 * Math.tan(fov* deg_to_rad / 2) * rotatedp.x))
{
return true;
}

return false;
}

public function touchingSight(rotatedp:Point):Boolean
{
var point1:Point = new Point(radius, radius*(Math.tan(fov * deg_to_rad/ 2)));
var point2:Point = new Point(radius, radius*( -1 * Math.tan(fov * deg_to_rad/ 2)));

var dist1:Number = segmentDistToPoint(new Point(0, 0), point1, rotatedp);
//trace("dist1: ", dist1);
if (dist1 < state.player.RADIUS)
{
//trace("dist1: ", dist1);
return true;
}

var dist2:Number = segmentDistToPoint(new Point(0, 0), point2, rotatedp);
if (dist2 < state.player.RADIUS)
{
//trace("dist2: ", dist2);
return true;
}

return false;
}

public static function segmentDistToPoint(segA:Point, segB:Point, p:Point):Number
{
var p2:Point = new Point(segB.x - segA.x, segB.y - segA.y);
var something:Number = p2.x*p2.x + p2.y*p2.y;
var u:Number = ((p.x - segA.x) * p2.x + (p.y - segA.y) * p2.y) / something;

if (u > 1)
u = 1;
else if (u < 0)
u = 0;

var x:Number = segA.x + u * p2.x;
var y:Number = segA.y + u * p2.y;

var dx:Number = x - p.x;
var dy:Number = y - p.y;

var dist:Number = Math.sqrt(dx*dx + dy*dy);

return dist;
}
}

}

7
games / AA31 - Tactical platformer
« on: Tue, Nov 12, 2013 »
More of a prototype so far, this is a platformer about passing undetected through a bunch of robots. My first flixel game. The one and only level here is just a test (in short, it has no level design). AA31 inherits the general characteristics of old-school platformers, but with a twist: you can't kill the enemies. You need to avoid detection, and you can hack enemies to reduce their speed, vision cone, etc.

PS: Flixel is awesome! And by the way, I notice small lags, but I'm guessing it's because of my crappy laptop. I went out of my way to optimize this as much as I could. I'd love to hear how it runs on other people's computers.

Currently I'm still trying to figure out a nice GUI for the hacking part. And the music is cutting off unexpectedly.

With all the swf stealing hype, I've decided to sitelock it here: http://ohmnivore.elementfx.com/210/aa31-game-engine-is-done/#.UpLQycSPSSo

8
help / FlxG.switchState() procedure help - SOLVED
« on: Mon, Oct 14, 2013 »
Well... I'm nearing the completion of a game prototype, and I have two states so far: the Menu state, and the Level state. Individually, they work well, but when I call FlxG.switchState from the menu state it gives me the following error:
[Fault] exception, information=TypeError: Error #1009: Cannot access a property or method of a null object reference.

Ah, heck, the famous 1009. FlashDevelop also points me to line 394 in FlxSprite (_flashRect.x = 0;).  ???

Now this is where my problem ends and my questions begin.
How should I go about switching states? I read that Flixel calls delete on all objects attached to the state. That's great. But is there anything else I should call delete upon? What about static FlxObjects and the like? Also, I'm an AS3 noob, so please don't kill me for this: should I set all properties to null?

...and here's the relevant code (not that I mind sharing all of it, but I don't find it necessary yet)
Menu class (extends Level class)
Code: [Select]
package 
{
import org.flixel.FlxButton;
import org.flixel.FlxG;
import org.flixel.FlxGroup;
import org.flixel.FlxObject;
import org.flixel.FlxPoint;
import org.flixel.FlxSprite;
import org.flixel.FlxText;
import org.flixel.plugin.photonstorm.FlxButtonPlus;

public class Menu extends Level
{
public var viewpoint:FlxObject = new FlxObject(0, 0, 1, 1);
internal var menuhud:FlxGroup = new FlxGroup();
internal var credits:Boolean = false;
internal var play:Boolean = false;
internal var playtext:FlxButton;
internal var credittext:FlxButton;
internal var kcredits:String;

public function Menu()
{
super(0);
player.active = false;
player.visible = false;
player.gun.active = false;
player.gun.visible = false;
hud.active = false;
hud.visible = false;
viewpoint.y = collidemap.height / 2;
}

override public function create():void
{
super.create();

kcredits = "Coded by Ohmnivore (at ohmnivore.elementfx.com) using Flixel and Flixel Power Tools. Cheers!";

FlxG.camera.follow(viewpoint, 0);
var splash:FlxSprite = new FlxSprite(FlxG.width / 2 - 128, 60, Assets.SPLASH);
splash.scrollFactor = new FlxPoint(0,0);
add(splash);
add(menuhud);

crosshairs.visible = false;
FlxG.mouse.show();

createmenu();
}

override public function update():void
{
super.update();
viewpoint.x += 1;
if (viewpoint.x > collidemap.width) viewpoint.x = 0;
}

internal function createcredits():void
{
menuhud.clear();
menuhud.add(new Box(FlxG.width - 16, FlxG.height - 16, 8, 8, 0)._box);
createescape();
var creditdisplay:FlxText = new FlxText(16, 16, FlxG.width - 32, kcredits);
creditdisplay.scrollFactor = new FlxPoint(0, 0);
menuhud.add(creditdisplay);
}

internal function createlvls():void
{
menuhud.clear();
menuhud.add(new Box(FlxG.width - 16, FlxG.height - 16, 8, 8, 0)._box);
createescape();
var numberolvls:uint = Assets.LVLS.length;
for (var currentlvl:uint = 1; currentlvl < numberolvls;  currentlvl++)
{
var hinttext:FlxText = new FlxText(16, 16, 100, "Choose a level");
hinttext.scrollFactor = new FlxPoint(0, 0);
menuhud.add(hinttext);

var lvlbutton:FlxButton = new FlxButton(16 + 96 * currentlvl, 16, String(currentlvl), loadlvl, currentlvl);
lvlbutton.scrollFactor = new FlxPoint(0, 0);
//lvlbutton.
menuhud.add(lvlbutton);
}
}

internal function createmenu():void
{
menuhud.clear();
playtext = new FlxButton(20,140,"Play",createlvls);
playtext.scrollFactor = new FlxPoint(0, 0);
playtext.x = FlxG.width / 2 - playtext.width / 2;
menuhud.add(playtext);

credittext = new FlxButton(20,160,"Credits",createcredits);
credittext.scrollFactor = new FlxPoint(0, 0);
credittext.x = FlxG.width / 2 - credittext.width / 2;
menuhud.add(credittext);
}

internal function createescape():void
{
var escaper:FlxButton = new FlxButton(20, FlxG.height - 50, "Return", createmenu);
escaper.scrollFactor = new FlxPoint(0, 0);
escaper.x = FlxG.width / 2 - escaper.width / 2;
menuhud.add(escaper);
}

internal function loadlvl(lvltoload:uint):void
{
trace(lvltoload);
FlxG.switchState(new Level(lvltoload));
}

override public function destroy():void
{
super.destroy();
}
}

}

Level class (extends FlxState)
Code: [Select]
package 
{
import org.flixel.*;
import org.flixel.plugin.photonstorm.*;
import FlxDialog;
import BTNTilemap;
import org.flixel.plugin.photonstorm.FX.GlitchFX;

public class Level extends FlxState
{
public static var crosshairs:AnimatedCursor;

public var asset:Assets;
public var player:Player;
public var collidemap:BTNTilemap;
public var bullets:FlxGroup;
public var charoverlay:FlxGroup;
public var charunderlay:FlxGroup;
public var emitters:FlxGroup;
public var hud:FlxGroup;
public var powerups:FlxGroup;
public var enemies:FlxGroup;
public var lasers:FlxGroup;
public var stars;
public var initcpu:uint;
public static var maps:Array = new Array();
public static var mapz:Array = new Array();
public static var lazzz:Array = new Array();
public var chats:Array = new Array();
public var levelindex:uint;

public function Level(Levelindex:uint)
{
super();
levelindex = Levelindex;
powerups = new FlxGroup();
enemies = new FlxGroup();
lasers = new FlxGroup();
bullets = new FlxGroup();
charoverlay = new FlxGroup();
charunderlay = new FlxGroup();
emitters = new FlxGroup();
hud = new FlxGroup();
asset = new Assets();

//initcpu = 10;
initcpu = int(Assets.LVLS[levelindex][4]);

//var container:Object = asset.bigList[0]["1"];

if (FlxG.getPlugin(FlxSpecialFX) == null)
{
FlxG.addPlugin(new FlxSpecialFX);
}

if (FlxG.getPlugin(FlxMouseControl) == null)
{
FlxG.addPlugin(new FlxMouseControl);
}

//Load lasers
//for (var laser:int = 0; laser < Assets.LVLS[0][0].length; laser++)
//{
//lasers.add(new Laser(new FlxPoint(Assets.LVLS[0][0][laser][0], Assets.LVLS[0][0][laser][1]),
//new FlxPoint(Assets.LVLS[0][0][laser][2], Assets.LVLS[0][0][laser][3]), this));
//}

//Load map layers
for (var layer:int = 0; layer < Assets.LVLS[levelindex][3].length; layer++)
{
maps[layer] = new FlxTilemap;
mapz[layer] = new BTNTilemap;
if (Assets.LVLS[levelindex][3][layer][0] == 'Collide')
{
collidemap = mapz[layer].loadMap(Assets.LVLS[levelindex][3][layer][1], Assets.T_COLLIDE, 8, 8);
collidemap.setTileProperties(0, FlxObject.NONE);
collidemap.setTileProperties(1, FlxObject.ANY);
FlxG.worldBounds = new FlxRect(0, 0, collidemap.width, collidemap.height);
collidemap.visible = false;
//trace("collide");
}
if (Assets.LVLS[levelindex][3][layer][0] == 'Snow')
{
var frontmap:FlxTilemap;
frontmap = maps[layer].loadMap(Assets.LVLS[levelindex][3][layer][1], Assets.T_SNOW, 16, 16);
}
if (Assets.LVLS[levelindex][3][layer][0] == 'SnowBack')
{
var backmap:FlxTilemap;
backmap = maps[layer].loadMap(Assets.LVLS[levelindex][3][layer][1], Assets.T_SNOW, 16, 16);
backmap.scrollFactor.x = backmap.scrollFactor.y = 0.8;
}
}

var back = new FlxSprite(-FlxG.width-100, -FlxG.height-100).makeGraphic(
collidemap.width + 2*FlxG.width + 200, collidemap.height + 2*FlxG.height + 200, 0x2269D2FF);
this.add(back);

this.add(collidemap);
this.add(backmap);
this.add(lasers);
this.add(frontmap);
this.add(emitters);
this.add(enemies);

player = new Player(0, 0, this);
//player.cpu = int(Assets.LVLS[0][4]);
this.add(player);

//var health:Powerup = new Powerup(50, 50, "AMMO", "ammo", 5);
//powerups.add(health);

this.add(powerups);
this.add(bullets);
this.add(charoverlay);
this.add(charunderlay);
//this.add(emitters);
this.add(hud);

var starfield = FlxSpecialFX.starfield();
starfield.setStarSpeed(FlxMath.rand(-1.5,1.5), FlxMath.rand(1,2));
//stars = starfield.create(0, 0, FlxG.width, FlxG.height, FlxMath.rand(50, 400), 1, 20, 0x0069D2FF);
stars = starfield.create(
-FlxG.width - 100, -FlxG.height - 100, collidemap.width + 2*FlxG.width + 200, collidemap.height + 2*FlxG.height + 200,
FlxMath.rand(50, 400), 1, 20, 0x0069D2FF);
stars.scrollFactor.x = stars.scrollFactor.y = 1.3;
this.add(stars);
}

override public function create():void
{
super.create();
FlxG.camera.follow(player, 1);
FlxG.worldBounds = new FlxRect(0, 0, collidemap.width, collidemap.height);
FlxG.mouse.hide();
crosshairs = new AnimatedCursor();
add(crosshairs);
//makeDialog();
FlxG.flash(0xffffffff);
//lasers.add(new Laser(new FlxPoint(10, 10), new FlxPoint(100, 50), this));
//var ab:FlxExtendedSprite = new FlxExtendedSprite(88, FlxG.height - 32, Assets.A_Disconnect);
//ab.scrollFactor = new FlxPoint(0, 0);
//ab.enableMouseDrag();
//hud.add(ab);
new HUDAbility(0, 0, "Disconnect", "health", 2, 1, this);
//FlxG.mouse.show();

//Load dialogs
for (var chat:int = 0; chat < Assets.LVLS[levelindex][2].length; chat++)
{
new Chat(Assets.LVLS[levelindex][2][chat].x,Assets.LVLS[levelindex][2][chat].y,Assets.LVLS[levelindex][2][chat].w,Assets.LVLS[levelindex][2][chat].h,Assets.LVLS[levelindex][2][chat].t,this);
}

//Load enemies
for (var enem:int = 0; enem < Assets.LVLS[levelindex][1].length; enem++)
{
switch (Assets.LVLS[levelindex][1][enem][2])
{
case "ZBot":
enemies.add(new ZRobot(Assets.LVLS[levelindex][1][enem][0], Assets.LVLS[levelindex][1][enem][1], this));
break;
case "Ammo":
powerups.add(new Powerup(Assets.LVLS[levelindex][1][enem][0], Assets.LVLS[levelindex][1][enem][1], "AMMO", "ammo", 2));
break;
case "Life":
powerups.add(new Powerup(Assets.LVLS[levelindex][1][enem][0], Assets.LVLS[levelindex][1][enem][1], "LIFE", "health", 2));
break;
case "Player":
player.x = Assets.LVLS[levelindex][1][enem][0];
player.y = Assets.LVLS[levelindex][1][enem][1];
break;
}
}

//Load lasers
for (var laser:int = 0; laser < Assets.LVLS[levelindex][0].length; laser++)
{
//lazzz[laser] = new Laser(new FlxPoint(int(Assets.LVLS[0][0][laser][0]/2), int(Assets.LVLS[0][0][laser][1])/2),
//new FlxPoint(int(Assets.LVLS[0][0][laser][2])/2, int(Assets.LVLS[0][0][laser][3])/2), this);
//lasers.add(lazzz[laser]);
//trace("Laser");
//trace(Assets.LVLS[0][0][laser][0],Assets.LVLS[0][0][laser][1],Assets.LVLS[0][0][laser][2],Assets.LVLS[0][0][laser][3]);
}
}

override public function update():void
{
super.update();
for each (var chatt:Chat in chats)
{
chatt.update();
}
hud.update();
//collidemap.
if (FlxG.mouse.y > FlxG.height - 64)
{
//FlxG.timeScale = 0;
}
else
{
FlxG.timeScale = 1.0;
}
FlxG.collide(collidemap, player);
FlxG.collide(collidemap, enemies);
FlxG.collide(collidemap, emitters);
FlxG.collide(collidemap, bullets, deletebullet);
FlxG.collide(collidemap, powerups);
FlxG.SEPARATE = false;
FlxG.collide(enemies, bullets, hit);
//FlxG.collide(player, enemies, );
FlxG.SEPARATE = true;
FlxG.collide(player, enemies, bumphandler);
FlxG.collide(player, powerups, poweruphandler);
for each (var laser:Laser in lasers.members)
{
if (FlxCollision.pixelPerfectCheck(laser, player, 255))
{
player.hurtchar(2);
}
}
}

public function bumphandler(Object1:FlxObject, Object2):void
{
Object2.bump();
}

public function poweruphandler(Object1:FlxObject, Object2:Powerup):void
{
Object2.activate(Object1);
}

public function makeDialog():void
{
var tx:FlxDialog = new FlxDialog(64,FlxG.height-64,FlxG.width-64,64,0.05, "JACK");
tx.showDialog(["Hey wassup bro!","How are you today?"]);
tx.setFormat(null, 10, 0xff000000, null, 0xff000000);
//tx.finishCallback = UpdateScript;
this.add(tx);
}

internal function makeBox(group:FlxGroup, text:String, X:Number = 32, Y:Number = 32, columns:int = 1, scroll:Number = 0):void
{
var _box:FlxGroup = new Box((text.length * 16 - (text.length * 16) % 24) + 48, columns*24+24, X-12, Y-12, scroll)._box;
group.add(_box);
}

public function hit(Object1:FlxObject, Object2:FlxObject):void
{
Object1.health -= player.damage;
Object1.flicker(0.2);
Object2.kill();
//Object2.destroy();
}

public function deletebullet(Object1:FlxObject, Object2:FlxObject):void
{
var emitter:FlxEmitter = new FlxEmitter(Object2.x+4,Object2.y+4); //x and y of the emitter
var particles:int = 7;

for(var i:int = 0; i < particles; i++)
{
var particle:FlxParticle = new FlxParticle();
particle.makeGraphic(3, 3, 0xffffffff);
particle.exists = false;
emitter.add(particle);
}

emitters.add(emitter);
emitter.start();
emitter.lifespan = 1;

var emitter2:FlxEmitter = new FlxEmitter(Object2.x+4,Object2.y+4); //x and y of the emitter
var particles2:int = 4;

for(var i2:int = 0; i2 < particles2; i2++)
{
var particle2:FlxParticle = new FlxParticle();
particle2.makeGraphic(3, 3, 0xffffffff);
particle2.exists = false;
emitter2.add(particle2);
}

this.add(emitter2);
emitter2.start();
emitter2.lifespan = 0.5;
Object2.kill();
}
}

}

9
chat / Class for dynamically creating HUD boxes
« on: Sun, Oct 6, 2013 »

Well, I feel like sharing this class, as I think every game could use it and it's no use that every game re-writes it.  8)
What it does is create an FlxGroup that contains all the box's sprites. Add _box to your FlxState and you're good to go.

For instance:
_bg = new Box(FlxG.width, 64, 0, FlxG.height-64, 0)._box;
add(_bg);

constructor: width,height,x,y,scrollfactor for x and y

The SIDELENGTH constant is the length of your graphic's sides in pixels. The graphics are the 9 images that you need to embed yourself. Right top corner, left top corner, right bottom corner, left bottom corner, right side, left side, bottom, top, center.

Of course that's a crap explanation so here's the images I use for my game. I think that by looking at them you'll get the idea.













And here's the class:
Code: [Select]
package 
{
import org.flixel.FlxGroup;
    import org.flixel.FlxSprite;

public class Box
{
internal const SIDELENGTH:uint = 8;

[Embed(source = "art/b_bot_l.png")]
internal var _b_bot_l:Class;

[Embed(source = "art/b_bot_r.png")]
internal var _b_bot_r:Class;

[Embed(source = "art/b_top_l.png")]
internal var _b_top_l:Class;

[Embed(source = "art/b_top_r.png")]
internal var _b_top_r:Class;

[Embed(source = "art/b_bot.png")]
internal var _b_bot:Class;

[Embed(source = "art/b_top.png")]
internal var _b_top:Class;

[Embed(source = "art/b_middle.png")]
internal var _b_middle:Class;

[Embed(source = "art/b_r.png")]
internal var _b_r:Class;

[Embed(source = "art/b_l.png")]
internal var _b_l:Class;

public var _box:FlxGroup = new FlxGroup();

public function Box(width:int = 80, height:int = 32, X:Number = 0, Y:Number = 0, scroll:Number = 0)
{
var x:int = 0;
var y:int = 0;
_box.add(new FlxSprite(x, y, _b_top_l));
_box.add(new FlxSprite(width - SIDELENGTH, y, _b_top_r));
_box.add(new FlxSprite(width - SIDELENGTH, height - SIDELENGTH, _b_bot_r));
_box.add(new FlxSprite(x, height - SIDELENGTH, _b_bot_l));
x = SIDELENGTH;
for (x; x < width - SIDELENGTH; x+=SIDELENGTH)
{
_box.add(new FlxSprite(x,y,_b_top));
}
x = SIDELENGTH;
y = height - SIDELENGTH;
for (x; x < width - SIDELENGTH; x+=SIDELENGTH)
{
_box.add(new FlxSprite(x,y,_b_bot));
}
x = 0;
y = SIDELENGTH;
for (y; y < height - SIDELENGTH; y+=SIDELENGTH)
{
_box.add(new FlxSprite(x,y,_b_l));
}
x = width - SIDELENGTH;
y = SIDELENGTH;
for (y; y < height - SIDELENGTH; y+=SIDELENGTH)
{
_box.add(new FlxSprite(x,y,_b_r));
}
x = SIDELENGTH;
for (x; x < width - SIDELENGTH; x += SIDELENGTH)
{
y = SIDELENGTH;
for (y; y < height - SIDELENGTH; y += SIDELENGTH) _box.add(new FlxSprite(x,y,_b_middle));
}

for each (var member in _box.members)
{
member.scrollFactor.x = member.scrollFactor.y = scroll;
member.x += X;
member.y += Y;
}
}
}
}

Pages: [1]