Last Good Quote: Son's are the seasoning on our lives. - Someone on Facebook

Wednesday, March 19

Articles on World Building

World Building and World Auto Generation

Simple Rogue Like -
http://kuoi.org/~kamikaze/GameDesign/art07_rogue_dungeon.php

Random 2D Tile Map Generation
http://stackoverflow.com/questions/11968167/random-2d-tile-map-generating-algorithm?rq=1


Tuesday, March 11

To My Son and My Future Self


I love you son. I want to be your friend. I want to be your confidant. I want to be your rock in stormy times. But I am your father first and foremost. That means I must prepare you for the world as best as I can. That means I must ask you to do better than me. That means I must ask of you the hard things in life. I must force you to confront your issues head on, with your head up and your eyes open. I apologize if in your youth this strains are relationship. But it is how things must be. I am your father.


You brought home poor grades, extremely poor grades. At first I was angry at you. Very Angry. I dreamed of ways to punish you and make you FEEL the retribution. How I would make you quake with the fear of god himself. Make you feel as if the very wrath of the world was upon your head. It felt good to think these things. Yes, I knew the exact methods I would take to ensure you could not contemplate a failure like this again. I had it figured out...down to the last belt stroke.


But I gave myself time. Time to simmer down. Time to realize that my anger was driven by something else. (A lesson you would be wise to learn: Anger is never the REAL reason, it is an excuse to take action). I realized that I was ashamed, embarrassed that a son of my genes, a boy with the creativity, wit and intelligence equal to my own, could not do moderately well in school. I was embarrassed because this was a public reflection of my lack of mentorship to you.  My lack of showing you how to apply discipline and persistence. My lack of teaching you what was important and what was not. It was not you who had failed, but I who had failed you. My lack of showing you how take on a challenge and succeed. This failure was on both of us. This was humbling.

I now contemplate a gentler approach, but one that will test the limits of our relationship. I will teach you how to do this thing. I will teach you how to excel at the game of life. Oh, there will be punishment but it will be with measured and calculated to demonstrate to you that there are immediate consequences for poor decision makings. Especially when one can choose a better road. Rewards will come as well, but not given cause you are "due" them, but given because you earned them by taking the harder, longer, less traveled road.

I do wonder at what point it was that this failure on my part began. I love you. I spend time with you. I take you out. I take you to hang out. I find friends for you. I taught you how to talk, walk, read, ride a bike. Never let it be said that I did not care and spend time with my son.

But I was never hard on you. Never. And shame on me for it. I claimed I wanted you to have a “nice” childhood. Not realizing that in the “roughness” of a no, there is a challenge to the little mind. A challenge to the idea that not all things come by way of words, tears, smiles and hugs. But the idea that some things only come by the hard work of your own hands. In wanting you to have an easier time of childhood, an easier one than mine, I made you unable to handle struggle.

You're 14. Maybe you are too old, I hope not. But change is in the air. I know this will start a war between the two of us. I know at your current age you will not understand. I know we may no longer be friends....for a time. This makes me terribly sad. But I know this is my responsibility. I know this right. I know this is what I need to do .... for you.

We start on this journey tonight, March 10th of 2014. I hope I have the fortitude to stay with this. I do this for myself, I do this for you and I do this for the future generations. I love you son.

Your Father,
Markus Beamer

Why:
I write this in the heat of the moment. I write it cause I have to catch this anger and bottle it up and use it to fuel me to do the right thing. I write it so one day in the far future you will know I did these things for the right reason. However it works out.

I make this public because a public declaration of intention is the strongest way to re-enforce me taking personal actions.

I also know that I am not the only one struggling with this issue, it is driven from a true love for my children. Hopefully others can learn from my mistakes.

Saturday, March 1

Spawning Monsters

I've been thinking about monster spawning. For those that might now know, this means to place a new enemy creature on a map. A few thoughts I have.

As I develop the monster spawning will get progressively complex, so this is an iterative approach.

Variables:
MaxMonstersNearBy
Spawn Point - Coordinates of spawn point
Spawn Radius - As a player moves monsters will spawn within this area


  1. Check if there is more than MaxMonstersNearBy, if so exit. MaxMonstersNearBy will be set by the particular segment of the map the player is on.
  2. Check if there any players within viewing distance of the spawn point. If so exit. We don't want monsters to "pop" on the screen, players will wonder into them, or monsters will wonder into players
  3. Spawners will have a maximum number of monsters they can have spawned at any point in time.
  4. Check if there any spawn points outside of viewing distance but within SpawnRadius of the player. For each spawn point proceed.
    1. Choose a random leader, whose level is within 1 level of the player.
    2. Leaders have a number of followers that will spawn with them.
    3. Place the leader and the followers on an empty spot near the spawn point.

AI:
  1. Monsters will have one of the follow modes specified:
    1. Attack - Aggressively chase any player within x distance
    2. Guard - Stay still and attack only when attacked
    3. Wander - Moves randomly in a direction
    4. Follow - Follow a given unit, in the event that unit can not be found, start to wander.
  2. Leaders will set the mode of all followers
  3. Followers with no leader will go into wander mode.
Realistic Movement:
  1. Recall that AI processing (aiThinker) is only called once every few seconds.
  2. AI will choose 5 waypoints and move between those waypoints until the aiThinker is called again.
This is for my game Blades of War.



Thursday, February 20

Creating and Populating a Date Dimension

declare @startDateID int = 20130101
declare @endDateID int =20131231 -- 20141231
declare @truncate char(1) = 'Y'
declare @currDateID int = @startDateID
declare @currDate datetime

select @currDate = Convert(DATETIME, LEFT(@startDateID, 8))

if(@truncate = 'Y')
begin
truncate table dim_date
end

while(@currDateID <= @endDateID)
begin

select @currDate = Convert(DATETIME, LEFT(@currDateID, 8))
--print convert(varchar,@currDate)

insert into dim_date(dateID, fullDate)
values (@currDateID, @currDate)

set @currDate = DATEADD(d,1,@currDate)
set @currDateID = CONVERT(varchar,@currDate,112)


end

--
-- you may have to do something special here, or you can mark all days as tradeable
--
update dim_date set isTradeDay = 'Y'
where dateID in (select closeDateID
from stock_history
group by closeDateID
having COUNT(*) > 1000)






select @currDate = Convert(DATETIME, LEFT(@startDateID, 8))
set @currDateID = @startDateID

declare @priorDateID int
declare @prior5DateID int
declare @prior10DateID int
declare @prior30DateID int
declare @prior60DateID int
declare @prior90DateID int
declare @prior180DateID int
declare @futureDateID int
declare @future5DateID int
declare @future10DateID int
declare @future30DateID int
declare @future60DateID int
declare @future90DateID int
declare @future180DateID int

while(@currDateID <= @endDateID)
begin

select @currDate = Convert(DATETIME, LEFT(@currDateID, 8))
print convert(varchar,@currDate)

select @priorDateID = MAX(dateID) from dim_date where dateID < @currDateID and isTradeDay = 'Y'
select @prior5DateID = Min(dateID) from (select top 5 dateID from dim_date where dateID < @currDateID and isTradeDay = 'Y' order by dateID desc) as a
select @prior10DateID = Min(dateID) from (select top 10 dateID from dim_date where dateID < @currDateID and isTradeDay = 'Y' order by dateID desc) as a
select @prior30DateID = Min(dateID) from (select top 30 dateID from dim_date where dateID < @currDateID and isTradeDay = 'Y' order by dateID desc) as a
select @prior60DateID = Min(dateID) from (select top 60 dateID from dim_date where dateID < @currDateID and isTradeDay = 'Y' order by dateID desc) as a
select @prior90DateID = Min(dateID) from (select top 90 dateID from dim_date where dateID < @currDateID and isTradeDay = 'Y' order by dateID desc) as a
select @prior180DateID = Min(dateID) from (select top 180 dateID from dim_date where dateID < @currDateID and isTradeDay = 'Y' order by dateID desc) as a

select @futureDateID = MIN(dateID) from dim_date where dateID > @currDateID and isTradeDay = 'Y'
select @future5DateID = Max(dateID) from (select top 5 dateID from dim_date where dateID > @currDateID and isTradeDay = 'Y' order by dateID ) as a
select @future10DateID = Max(dateID) from (select top 10 dateID from dim_date where dateID > @currDateID and isTradeDay = 'Y' order by dateID ) as a
select @future30DateID = Max(dateID) from (select top 30 dateID from dim_date where dateID > @currDateID and isTradeDay = 'Y' order by dateID ) as a
select @future60DateID = Max(dateID) from (select top 60 dateID from dim_date where dateID > @currDateID and isTradeDay = 'Y' order by dateID ) as a
select @future90DateID = Max(dateID) from (select top 90 dateID from dim_date where dateID > @currDateID and isTradeDay = 'Y' order by dateID ) as a
select @future180DateID = Max(dateID) from (select top 180 dateID from dim_date where dateID > @currDateID and isTradeDay = 'Y' order by dateID ) as a

--select Max(dateID) from (select top 5 dateID from dim_date where dateID > 20130115 and isTradeDay = 'Y' order by dateID ) as a
--select Max(dateID) from (select top 10 dateID from dim_date where dateID > 20130115 and isTradeDay = 'Y' order by dateID ) as a


update dim_date
set priorDateID = @priorDateID
,prior5DateID = @prior5DateID
,prior10DateID = @prior10DateID
,prior30DateID = @prior30DateID
,prior60DateID = @prior60DateID
,prior90DateID = @prior90DateID
,prior180DateID = @prior180DateID

,futureDateID = @futureDateID
,future5DateID = @future5DateID
,future10DateID = @future10DateID
,future30DateID = @future30DateID
,future60DateID = @future60DateID
,future90DateID = @future90DateID
,future180DateID = @future180DateID

where dateID = @currDateID

set @currDate = DATEADD(d,1,@currDate)
set @currDateID = CONVERT(varchar,@currDate,112)


end




select * from dim_date where dateID between 20130210 and 20130230

Monday, November 25

How to Build a Trading Indicator

Interesting read...

http://www.investopedia.com/articles/trading/04/120804.asp

Saturday, November 16

Particle Emitters - Part III

And here are the actual effects themselves. It generates the actual effect:


function WhirlEmitter(point,color)
{
    this.position = point; // Vector
    this.velocity = Vector.fromAngle(0,.5); // Vector
    this.spread = Math.PI/1; // possible angles = velocity +/- spread
    this.drawColor = "#999"; // So we can tell them apart from Fields later
    this.particleColor = color;
    this.maxParticles = 100;
    this.particleSize = 1;
    this.numParticles = 0;
    this.emissionRate = 1;
    this.tether = rand(60,100);
}

WhirlEmitter.prototype.emit = function()
{
    var angle = this.velocity.getAngle() + this.spread - (Math.random() * this.spread * 2);
    var magnitude = this.velocity.getMagnitude();

    var velocity = new Vector(0,0);//Vector.fromAngle(angle, magnitude);
    var position = new Vector(this.position.x + velocity.x * 25, this.position.y + velocity.y * 25);
    var particle = new Particle(position,velocity,new Vector(0,0),this.particleColor,2);
    particle.action = "whirlParticle";
    particle.particleColor = this.particleColor;//'rgb(' + rand(0,255) + ','+ rand(0,255) + ','+ rand(0,255) + ')'
    particle.tether = rand(1,360)/100;
    particle.origin = new Vector(this.position.x, this.position.y);

    //this.position.x++;
    return particle;
};


function whirlParticle(particle)
{
    //alert(particle.life + ":" + particle.tether);
    var tmpX = particle.origin.x + particle.radius * Math.cos(particle.tether);
    var tmpY = particle.origin.y + particle.radius * Math.sin(particle.tether);
    particle.position = new Vector(tmpX, tmpY);
    particle.tether+=.25;
    particle.particleSize-=.01;
   
    if(particle.tether > 7)
    {
        particle.tether = .36;
        particle.radius-=5;
    }
   
    if(particle.radius < 0 || particle.particleSize <= 0)
    {
        return "";
    }

    return particle;
}

Saturday, November 9

Particle Emitters - Part II

Check out the Particle Emitters Series to get the full picture.

There are some basic functions that are needed for to make this work, they are as follows. We won't be modify this much except for the plotParticles function, where we have to change the if statements for each of our effects. (I know there must be a clever way to do this, but I ran outta time)


function Particle(point, velocity, acceleration,color,size) {
  this.position = point || new Vector(0, 0);
  this.velocity = velocity || new Vector(0, 0);
  this.acceleration = acceleration || new Vector(0, 0);
  this.origin = new Vector(0,0);
  this.color = color
  this.particleSize = size;
  this.action = "";
  this.life = 0;
  this.tether = 0;
  this.radius = 25;
}

function plotParticles(boundsX, boundsY)
{
    // a new array to hold particles within our bounds
    var currentParticles = [];

    for (var i = 0; i < particles.length; i++)
    {
        var particle = particles[i];

       
        var pos = particle.position;

               
        if(particle.action == "warpParticle")
        {
            particle = warpParticle(particle);
            particle.move();
        }

        if(particle.action == "whirlParticle")
        {
            particle = whirlParticle(particle);
        }
       
        if(particle.action == "beamParticle")
        {
            particle = beamParticle(particle);
        }
       
       
        if(particle != "")
        {
            // If we're out of bounds, drop this particle and move on to the next
            if (pos.x < 0 || pos.x > boundsX || pos.y < 0 || pos.y > boundsY) continue;
            if (particle.particleSize <= 0) continue;

           
            // Add this particle to the list of current particles
            currentParticles.push(particle);
        }
    }

    // Update our global particles, clearing room for old particles to be collected
    particles = currentParticles;
}



function rand(from,to)
{
    return Math.floor(Math.random()*(to-from+1)+from);
}


function drawParticles()
{
    // For each particle
    for (var i = 0; i < particles.length; i++)
    {
        context.fillStyle = particles[i].color;
        var position = particles[i].position;
        //context.fillRect(position.x, position.y, particles[i].particleSize, particles[i].particleSize);

        context.fillStyle = particles[i].particleColor;
        context.beginPath();
        context.arc(position.x, position.y, particles[i].particleSize, 0, Math.PI * 2);
        context.closePath();
        context.fill();

    }
}


function addNewParticles()
{
    for (var i = 0; i < emitters.length; i++)
    {
        if(emitters[i].numParticles < emitters[i].maxParticles)
        {
            for (var j = 0; j < emitters[i].emissionRate; j++)
            {
                particles.push(emitters[i].emit());
                emitters[i].numParticles++;
            }
        }

    }
}



Particle.prototype.move = function () {
  // Add our current acceleration to our current velocity
  this.velocity.add(this.acceleration);

  // Add our current velocity to our position
  this.position.add(this.velocity);
};



function Vector(x, y) {
  this.x = x || 0;
  this.y = y || 0;
}

// Add a vector to another
Vector.prototype.add = function(vector) {
  this.x += vector.x;
  this.y += vector.y;
}

// Gets the length of the vector
Vector.prototype.getMagnitude = function () {
  return Math.sqrt(this.x * this.x + this.y * this.y);
};

// Gets the angle accounting for the quadrant we're in
Vector.prototype.getAngle = function () {
  return Math.atan2(this.y,this.x);
};

// Allows us to get a new vector from angle and magnitude
Vector.fromAngle = function (angle, magnitude) {
  return new Vector(magnitude * Math.cos(angle), magnitude * Math.sin(angle));
};

Saturday, November 2

Particle Emitters - Part I

I've been playing around with Particle Emitters. Those are the cool little animations like star bursts and flowing bubbles that you see in games.

I used the following as a blank canvas for me to work with:

(notice you will need particleFunctions,js and particleEffects.js which are coming in part II and III)

<html>
  <head>
    <script language=javascript src="particleFunctions.js"></script>
    <script language=javascript src="particleEffects.js"></script>
  </head>
  <body>
    <canvas    style="width:300px; height:300px;border:1px solid black;background:black;" width=300 height=300></canvas>
<script>
var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
var particles = [];
emitters = new Array();
emitters.push(new WhirlEmitter(new Vector(canvas.width/2+5,canvas.height/2),'green'));
emitters.push(new BeamEmitter(new Vector(canvas.width/2,canvas.height/2),'green'));
    
function loop() {
    clear();
    update();
    draw();
    queue();
}

function clear() {
  context.clearRect(0, 0, canvas.width, canvas.height);
}

function queue() {
  window.requestAnimationFrame(loop);
}

function update() {
  addNewParticles();
  plotParticles(canvas.width, canvas.height);
}

function draw() {
    drawParticles();
}

loop();
</script>

    </body>
</html>

Monday, October 28

Quote

Great leaders are almost always great simplifiers, who can cut through argument, debate and doubt, to offer a solution everybody can understand.


Saturday, October 26

Logi - Secure Key in 3 Steps

Secure Key  Authorization or Single Sign On integration is a popular item that requires reviewing with a lot of the clients I have dealt with.

This might help.

First Step: Leave your current login/authorization in place. You won't need to make modifications to it.

Second Step:
When your users click a link in your site that opens a Logi report, or opens the Logi portal you have built you will need to perform the secure key authentication at this point. If I had a C# application I might code it up as follows:

protected void rptLink_Click(object sender, EventArgs e)
{
StringBuilder lgxSecureKeyUrl = new StringBuilder("http://localhost/myLogiApp/);

//add the constant location of secure key handler in Logi
lgxSecureKeyUrl.Append("rdTemplate/rdGetSecureKey.aspx");

//The username is required (this could also be the UserID that you use to secure the app)
lgxSecureKeyUrl.Append("?Username=99999");

//You can pass roles and rights if you have them allready
lgxSecureKeyUrl.Append("&Roles=Manager,Admin");
lgxSecureKeyUrl.Append("&Rights=ViewReportList,ViewReports,CreateDashboards");

//this needs to be the USERS ip address
lgxSecureKeyUrl.Append("&ClientBrowserAddress=127.0.0.1");

//shoot the request over to Logi
HttpWebRequest lgxSecureKeyReq = (HttpWebRequest) HttpWebRequest.Create(lgxSecureKeyUrl.ToString());

//the response will be a secure key that is good for a single one time use
HttpWebResponse lgxSecureKeyResp = (HttpWebResponse)lgxSecureKeyReq.GetResponse();
StreamReader sr = new StreamReader(lgxSecureKeyResp.GetResponseStream());
string lgxSecureKey = sr.ReadToEnd();

//you will now send the user to your Logi app with that secure key
//logi will take it from there
StringBuilder lgxReportUrl = new StringBuilder("http://localhost/myLogiApp/rdPage.aspx?rdReport=Default");

//dont forget the secure key
lgxReportUrl.Append("&rdSecureKey=");
lgxReportUrl.Append(lgxSecureKey);

//send the user in what ever way you want
Response.Redirect(lgxReportUrl.ToString());
}

Third Step:
To setup Logi to handle the secure, you will edit the _Settings file.

Add a Security Element with the following settings:

  • Authentication Source: Secure Key
  • Authentication Client Address: [server ip] 
  • Cache Rights and Roles: Session
  • Restart Session: True
  • Security Enabled: True
That should do it for you

Troubleshooting:

The secure key is only good for one request, so if you submit the link and then click refresh, you will get an error as authentication fails. This is intentional. Notice the secure key is in the url when you refreshed.

Passing your UserID in the username is the best way to handle authentication, as then you can query and store any additional information you need using that key.

Keep in mind the rdGetSecureKey request is taking place between your primary server and the logi application





Followers