Archive
Smart Mobile Studio does Oculus Rift VR
Well this is going to be fun! My boss came into my office today and gave me a strange box, saying “you like stuff like this right? Take it home and enjoy”. So now I have my nerdy hands on the Oculus. So you can probably guess what I’ll be doing the next couple of weeks? Thats right, OpenGL with Smart Mobile Studio!
In defense of Peter Molyneux and the so-called Godus scandal
If you don’t know about Peter Molyneux, his background or what has happened lately, this post might seem odd. He most certainly doesn’t use Delphi or Smart Mobile Studio (as far as I know), so what exactly does Peter Molyneux have to do with my blog? Well, as an old Amiga developer the name Peter Molyneux is practically a household name where I come from.
To make a long story short, Peter Molyneux is a game developer. He started back in the 90’s with Bullfrog Software, knocking out games like Populous for the 16 bit Amiga and Atari computers. In fact, he is probably one of the most successful software developers in Europe, and his story is one that every developer, no matter what language you prefer, can learn from. Both the good parts and the negative bits (which for the past 18 months has been blown utterly out of proportions).
The past 20 years so so has been full of change for Peter. Bullfrog software was sold, and he went on to become a game publisher or architect of sorts rather than “just another recognized coder”. His latest company is called “22 cans”, and for some reason it’s become the target of scandal, slander and near suicidal mongering, demanding Peter’s head on a platter.
To make a long story short:
Peter and his team went on kickstarter to raise money for a game called Godus. It’s really just a re-creation and expansion of the old Populous game – a game where you play a deity for a tribe of people, helping them and controlling their evolution. Or you can just be a complete ass-hat of a god and make their lives a living hell. The novelty of Godus over the now ancient Populous is naturally the wonderful graphics modern computers can muster up, and also the inter-connectivity we expect and enjoy on a daily basis. So the Godus game represents a huge universe where all the tribes and lands, represented by every player, is also connected.
Sounds like fun? It sure does. You can expect battles, co-operation between tribes and all the mythical mayhem of becoming “the god of gods”. A blasphemy of epic proportions to all religions of the world, but peter has never bothered to much about that.
Read: Rock, Paper Shotgun interview with Monyneux here.
Read: The guardian on Peter and his “failure” here.
The great scandal
But sadly, things havent gone to well for Peter and his crew. It would seem that most of the pledgers are PC and Mac users, so they were quite disappointed when 22 cans released the mobile version first (iPad, iPhone and Android versions).
Peter then went ahead and cut down on staff, which in his own words were made up of a lot of young programmers – programmers that wanted to do something else. I can fully understand Peter on this, because it’s no use having programmers that dislike what they do. Sitting month after month coding stuff you ultimately find boring is a recipe for failure.
And what can you do? When someone sends written notification of resignation, you cant kidnap the programmers and force them to work. People come and leave all the time, that’s the truth for all software companies.
Sadly, pledgers regarded this move as a sort of “bailing out” of his promise to deliver the goods (or gods) on Kickstarter. The game is also 12 months over-due, so people immediately believe this has to do with Peter letting the younger programmers out of the project.
To make matters worse, some bloke which won a godus competition, earning the title “god of gods” wrote a heart breaking story of how he was invited to 22-cans offices, got invited out for a pub-crawl, and how Peter didnt really talk that much to him during the evening. I personally dont know what’s wrong with this player — what exactly did you expect? That Peter should have carried you on his shoulders all night? Why would you want to go to a pub with a bunch of coders you dont know anyhow. Why not just pick up the price (the name), get that in writing and go home? I sure as hell wouldnt bother going to their HQ just for a pub round to begin with.
And just when you think it cant get more complex, Peter has come up with another game project which he has allocated resources for. Once again I can completely understand why he did this, because that’s how creative people work. I am usually 2-3 titles behind my current project. So while i’m coding one project, my mind is busy designing the next release or some other piece of software I want to build.
This is no different than say, a painter allocating a day of the week to work on a second painting, even though he is hired to work 5 days on some official piece. There are 7 days a week after all, and what people do with their time is ultimately up to them. But I agree that it looks bad from the consumer point of view, where you are 1 year overdue and you start working on something else.
This last move has infuriated the hundreds of backers, who regard this as utter nonsense. The consensus now seem to be that Peter is a crook who has wasted both their time, trust and money.
Personally I feel that completely cutting Peter’s head off just because he is hyper-creative is a silly way of going about things. At worst it demonstrates the utter lack of understanding regarding software production, creativity and motivation by the raging mass of pledgers. The world of software design and publishing is much more complex than people like to imagine.
Yes, peter should have made a bigger effort to dazzle and impress the public, keeping some key deadlines and stop the silly silent treatment. But we must remember that there are human beings behind all this.
Real life, real code
Peter has been extremely unlucky with this project. And it all has to do with time, rather than cash. Making a good game is something that takes at least 2 years of hard work — and that is the very least amount of time you need to build a polished game. Most games take between 2 – 4 years to produce, and you can expect all manner of problems along the way.
What is unfortunate is that Peter has promised a miracle. Namely to deliver the PC version in six months (!). I can fully understand his thinking, because you should imagine that with a mobile edition already out – that most of the grunt work is done and can be simply imported, adjusted and re-compiled for PC or Mac. But that has turned out to be flawed thinking. A full on PC game (and Mac game) is a completely different ballgame.
Peter should have known this because he has produced and published a wide range of titles over the past 20 years.
Another factor that has turned bad for Peter and his team, is the new environment in which a game is produced. With kickstarter you are in effect nude and open to scrutiny by everyone backing the project. Every little detail or administrative decision is noticed, spread and picked up by people who have absolutely no context to judge weither it was right or wrong. This is not the case when producing a closed title. Peter is used to producing closed titles, which means the only scrutiny he faces are internal and hidden from sight of gamers and partners.
In Peter’s defense, just think about all the social and administrative challenges a 2-4 year programming marathon represents. Think of all those collisions that can occur within a small team during 4 years of working together. Arguments, disagreements, counter-productive slander, people quitting, people giving up on the project, illness ranging from the common cold to on-set depression. And that’s just human side of things! Now add to this administrative challenges, shareholder meetings, advertising, press released and more. it’s a pretty daunting list of work. And this is before we throw in technical challenges and the actual coding process.
Trust
What I feel is lacking from this debate is a fair dose of trust. Peter has delivered so much software over the years that, I find it hard to believe that he would suddenly fail in doing something he has been doing for 20 years.
Trust should also be boosted by the fact that the mobile version is already out and can be bought right now, and you can even check out the pre-release on Steam.
I think that Peter made a huge mistake in his time-to-market analysis, no doubt there — but cutting his head off and turning this into a “scandal” of epic proportion is utter rubbish. It’s a game company who over-shot their release by 12 months, it’s not the end of the world. Heck, some popular titles have been 5 years in the making (2 years overdue), so this is not something new.
I for one believe in Peter. I think he will deliver — and to be frank I don’t care how he delivers, as long as he keeps his promise. Had we been talking 2-3 years overdue, then I would be disappointed, but he is only human.
Final words
Peter Molyneux is a creative human being. He is a dreamer, and like all good dreamers he spends most of the day inside his own head. Like the great thinkers of our time and the past, he is in love with the reality of thoughts and ideas.
What can appear as jumping from one idea to another, changing focus rapidly, is actually how some people navigate the creative world. This is a challenge for all programmers. You start out with one idea, this idea suddenly attract better ideas along the same lines — and before you know it, you have arrived at “a much better idea”.
This is how great things are made, by people who travel around the inner-inner reality of creativity. If you are not creative yourself, then you probably wont understand what i’m talking about.
The real scandal here is that this creative process has been exposed to the public, and trying to explain these creative discussions in financial terms can be.. well, it seems whimsical where it’s really rock solid.
I feel sad for the people who orchestrates these public witch-hunts. It’s always the same – watching a “public trial” where the verdict is decided upon long before the trial starts.
Sure, Peter should have been more professional in this matter, but he has apologized for this (ad nauseum) so why people feel they must continue to grind the bones for months on-end — well it’s just fucking stupid.
So cheer up Peter, I know you’ll get the job done. And done properly.
Keyboard input for Smart Mobile Studio
Smart Mobile Studio provides a rich and well planned out RTL. However, the RTL does take for granted that you do know you way around HTML and that you write more hands-on code than some may be comfortable with.
One question I often get is “Why doesnt the KeyDown and KeyUp events work”. Well, they do! But the law of HTML5 is that no element can accept input (or have focus) without a tabindex being set first. And since many of the standard controls that ship with the RTL dont expect keyboard input (or need keyboard input for that matter), the key-target value was not set by default.
So the solution to why the keyboard event(s) don’t fire on your TW3Panels and other containers (including forms) is quite simply that. Here is how you get keyboard events working in your form:
procedure TForm1.InitializeForm; begin inherited; // Set the key-down event OnKeyDown:=Procedure (sender:TObject;Key:Integer) begin writeln(key); end; // set the key-up event OnClick:=procedure (sender:TObject) Begin if visible then self.SetFocus; end; // this makes the form a key-event target w3_setAttrib(self.handle,'tabindex',0); end;
Note: In the next update of Smart Mobile Studio, all TW3CustomControls initialize the tabindex automatically, so by default all controls will be initialized to accept keyboard input.
Plotting angles in Object Pascal
From time to time someone hears that I’m a software engineer, and immediately they add to the conversation “oh you must be so good at mathematics, I suck at Maths”. I wish! In fact my math skills are ordinary at best. Like most creative individuals I tend to only learn something when I really need it. And sadly this was a personality trait even in highschool so I had a hard time surviving Math classes (or the teachers had a hard time dealing with me is more precise, I got expelled for beating up two of them).
The result is that whenever I face a trigonometry problem, I really am the mercy of the internet and friends. So I have decided to do something about this. I mean, I am 41 years of age after all. So off I go to Amazon.com to order a “trig for dummies” book, as I scavenger my son’s math curriculum for clues 🙂
Why trig?
From what I understand, programmers seem to be divided in two groups; The first group believes angular calculations is a waste of time and should be avoided if you can, because interpolation delivers more or less the same results but at a fraction (pun intended) of the cpu cost. The second group like to apply “real world maths” onto the flat landscape of Our cardassian coordinate system, which costs more but tend to deliver accurate results down to the last pixel.
The problem for a person who doesn’t really know that much about trigonometry, is that: if you don’t know how to do it properly, then you can’t possibly know how to derive an alternative. In other words, how can I write code which yields the same results if I have no clue about either Method?
Oh, and I’m on a new PC which uppercases every single word by force, so if this post looks a mess – that’s why. Windows 8.1 is just the gift that keeps on giving..
Hands on stuff
Imagine for a second that you want to create a shooting game. You have a top-down view of a battlefield and some mini-soldiers running around at your command. Whenever you click an enemy on the map, your soldiers should attempt to get within range of the enemy, and then start shooting. But that doesnt mean every single shot actually hit’s the target.
Now shooting “in a direction” is not as easy as it sounds. If your soldier is positioned at 100,100 on-screen – and your target is at 260,49 “or there about”, it wouldn’t be much of a game if your soldier hits the target every single time. Also, the enemy soldier will be moving away from the hit-zone and shoot back.
Another thing to consider is the strength of the weapon. The bullet should, when missing it’s target, continue on its trajectory. It doesn’t fall dead to the floor when it reaches the x2,y2 region of the map.
So how do we calculate such a shot?
Well, in my head the first thing that came up was:
- Find the angle at which the enemy is positioned (pt2) from the soldier (pt1)
- Calculate a path from p1 THROUGH p2, continuing forever; Affected by speed, wind, resistance and the size of the map
Naturally the calculation of the path should not be “pre calculated”, that was just the first way for me to approach the problem. All games have a main-loop and each element on the screen is only slightly updated per-frame. When this happens very fast the game comes to life.
Interpolation
Using interpolation means that you update the position of the bullet by fractions. More or less dividing the total difference between start and stop into smaller “chunks” –and then iterating through these steps until you reach the goal. This allows us to calculate an array of TPointF (floating point x,y record) which goes from start-position towards the end-position. Should it miss the target it will simply continue past the original target co-ordinate and ultimately go out of sight. At which point the game-engine can choose to either just drop the sprite object all together, or allow it to continue without being rendered until it’s velocity results in a halt (or you hit something else). At which point it should also be eliminated from the update-loop).
This would be a quick and dirty interpolated Version (thanks for the example Primoz!):
function TForm1.BuildList(x1,y1,x2,y2:float):Array of TPointF; var x: Integer; mlen: Integer; begin (* Single point? *) if (x1=x2) and (y1=y2) then begin result.add(TPointF.Create(x1,y1)); end else begin (* Add start point *) result.add(TPointF.Create(x1,y1)); (* Calculate axis length. Note: This controls the amount of distance you expand from the original position towards the target *) mlen:= round( (abs(x1-x2) + abs(y1-y2)) ); (* calculate mid-part *) for x:=1 to mLen do result.add(TpointF.Create ( x1 + x/100 * (x2-x1), y1 + x/100 * (y2-y1) )); (* Add end-point *) result.add(TPointF.Create(x2,y2)); end; end;
Please note that this is just quick and dirty code. It pre-calculates a given path from X1,Y1 through X2,y2; which is not something you want to use in a game. There you want to have fast and small calculations per item which is repeated in sync With the screen-redraw.
But this solves my problem quite elegantly: being able to derive a position through a general direction.
Using angles
Angles are different, here I can use the initial idea on how to solve it: namely to first get the angle Pt2 is in conjunction With Pt1 – and then calculate a path through that angle.
function AngleOfLine(const P1, P2: TPointF): Double; begin Result := RadToDeg(ArcTan2((P2.Y - P1.Y),(P2.X - P1.X))); if Result < 0 then Result += 360; end; function TForm1.BuildList(x1,y1,x2,y2:float):Array of TPointF; var Angle: Float; start,stop: TPointF; x: Integer; begin //build and add starting point start:=TPointF.Create(x1,y1); result.add(start); //build end-point record stop:=TPointF.Create(x2,y2); //Get angle of PT2 in context With PT1 Angle:=AngleOfLine(start,stop); //Generate 100 Points along angle for x:=1 to 100 do begin X2 := X1 + X * COS(DegToRad(Angle)); Y2 := Y1 + X * SIN(DegToRad(Angle)); result.add(TpointF.Create(x2,y2)); end; result.add(stop); end;
Classifying it
Right, with those two Experiments behind me, I took the time to extract what I have learned into a record which represents a position. This record has functions which allows you to update the position using a next() mechanism – so you can quickly update a bunch of bullets in a main-game-loop.
This allows us to not only keep track of the position, but also to calculate the next step with a single call. Turning this into a class, or using it as a property of a “bullet” class should be easy enough later.
type TQTXPosition = record Start: TPointF; //Where the bullet is shot from Target: TPointF; //Where the bullet is shot towards Position: TPointF; //Current position of bullet Iterator: Integer; //iterator value DistanceToTarget: Float; //Approx distance between start and target function Beyond:Boolean; function Next:TPointF; function Create(x1,y1,x2,y2:Float):TQTXPosition;overload; function Create(aStart,aTarget:TPointF):TQTXPosition;overload; end; //############################################################################# // TQTXPosition //############################################################################# function TQTXPosition.Create(x1,y1,x2,y2:Float):TQTXPosition; begin result.start.x:=x1; result.start.y:=y1; result.target.x:=x2; result.target.y:=y2; result.iterator:=0; result.Position.X:=0; result.Position.Y:=0; result.DistanceToTarget:= round(( abs(result.start.x-result.target.x) + abs(result.start.y-result.target.y))); end; function TQTXPosition.Create(aStart,aTarget:TPointF):TQTXPosition; begin result.start:=aStart; result.target:=aTarget; result.iterator:=0; result.Position.X:=0; result.Position.Y:=0; result.DistanceToTarget:= round(( abs(result.start.x-result.target.x) + abs(result.start.y-result.target.y))); end; function TQTXPosition.Beyond:Boolean; begin result:=Iterator > DistanceToTarget; end; function TQTXPosition.Next:TPointF; begin inc(Iterator); Position.X:= Start.x + Iterator/100 * (Target.x-Start.x); Position.Y:= Start.y + Iterator/100 * (Target.y-Start.y); result:=Position; end;
The “NeXT” function simply adds 1 to the iterating value, calculates the NeXT position, and Returns it. You may want to place this in a real class to make it more smooth to work With. The constructors allows you to define where to start and the target aim. The Beyond() function Returns true if the bullet has passed the target aim, and the DistanceToTarget Field represents the approx distance from start to aim.
Again, this is quick and dirty stuff – but for a novice in trig’ like myself it’s easier to understand the idea of “angle” as “slant towards” and radians as “reaching out towards a circumference”. Well, I just ordered my “for dummies” book and will hopefully get this under wraps. Special thanks to Eric, Primoz and Jørn for giving me extremely simple starter pointers and one-liner examples of various topics. Suddenly what used to be very booring at school is becoming exciting and useful as an adult 🙂
Never to old to learn new stuff!
Vector math’s is what seems to be the best way to solve most of this, so that’s on my list.
Tip for teachers
There will always be young boys that hates theory. Most of these kids are visual and tend to approach problems by “seeing” them mentally, and as such pure theory is regarded (or experienced) as the most boring thing in the universe. But the same kids, often creative and inventive, loves video games!
So my tip for teachers who have students like that (or as wild as I was) is to try to find a context for knowledge that these kids can find useful. Had someone told me in school that I could use this to create games – I would have consumed the books as fast as i could, because coding games and demo’s was something I really loved doing.
In fact, co-sinus and sinus was something I got to grips with when coding a “sinus scroll text” at early high-school. But like all kids I was under the impression that adults had it wrong and we had nothing to learn from them.
So if you are a teacher, try to make math’s more interesting by connecting it with computer games and coding (if the pupil responds to that). Who knows, one of your worst pupils may turn out to be the one who actually uses what you taught decades lates 😉
Smart Mobile Studio: Null is not unassigned, and unassigned is NaN
When I started the Smart Mobile Studio project I had medium knowledge of Javascript, meaning that I had not used it for many years. To me JavaScript was a toy, used for scrolltexts and popup’s. Smart Mobile Studio was born out of a full investigation into many different languages, and it was then I noticed that JavaScript had come of age and could finally support a full object-model and Delphi like OOP RTL.
But still, after all this time there are aspects of JavaScript that just bugs me. Not because they are stupid, but because something simple should – in effect – remain simple. Why take something simple, like datatypes, and introduce a third state?
Unassigned is not null
We all know Boolean values. They can either be TRUE or FALSE. But experienced programmers will also know, that there are cases in programming where a result is neither true nor false. For instance, if you have a function called “CheckDBConnection” that validates that you are indeed connected to your database server — but suddenly a system exception occurs somewhere in the middle, before you can determine if the connection is valid or invalid, what value should you return?
In such a scenario it’s best to default the whole function to false, in fact I would start by setting the result to false and only report true after everything checks out. This is called pessimistic discrimination. Positive discrimination is when you write your code with the world-view that everything will be ok. You ignore stuff like faulty disks, memory leaks and other acts of God (or nature, or darwin or whatever you subscribe to) and just focus on the good stuff.
But if we are to be truthful and have a datatype meant to reflect real-life-states, then boolean would either have to be altered with a third state ( TRUE, FALSE and UNKNOWN) or we would need a whole new datatype.
Unassigned
Under JavaScript all variables, be they intrinsic or not, can have a third state, namely the unassigned state. This also means that NULL, which we like to believe is the same as NIL in pointer based languages, actually is a value. It’s not the same as zero which is a number by nature. Null means “I have no value, but at least we are talking about values”, while Unassigned means “I dont even know what a value is, let alone what I am supposed to contain”.
- Null is NIL to a language which supports VOID
- Void is null to a language without NIL
- Unassigned in void to a language which supports null
Annoyed yet? This means that testing even the most simple stuff in JavaScript requires a couple of extra steps to deliver the goods. For instance, in the QTX helper code you will find these snippets:
function TQTXVarHelper.IsObject:Boolean; begin asm @result = ((@self) !== undefined) && (typeof @self !== null) && (typeof @self === "object") && ((@self).length === undefined); end; end; function TQTXVarHelper.IsArray:boolean; begin asm @result = ((@self) !== undefined) && (typeof @self !== null) && (typeof @self === "object") && ((@self).length !== undefined); end; end; function TQTXVarHelper.IsUnassigned:Boolean; begin asm @result = (typeof @self === undefined); end; end;
Notice that the check code to see if a JS variable is an object ( a = { } ) or if it’s an array ( a = [] ) are identical. Why? Because they both register as an object. The only way to tell them apart is by checking if a length() function exists which only arrays have.
Also notice that undefined is checked before NULL, because if an array is undefined, JS will throw an exception when comparing it to NULL, which is a value (!)
It’s really best to code JavaScript before you are fully awake. I code my best stuff between my first cup of coffee and having my morning shower..
TQTXReader and TQTXWriter for Smart Mobile Studio
Storage has become a theme the past couple of weeks for Smart Mobile Studio. I have posted twice about the filesystem classes I have added to QTX, but I have also added more – much more! As you will see over the next weeks 🙂
Whenever you need to write or read data, you really end up with variants in HTML5. Javascript has this thing where everything is either an object (read: prototypical object) an array, or an intrinsic value. To make writing and reading named value pairs easier I have created two classes, cleverly called TQTXReader and TQTXWriter.
The writer allows you to, well.. write into a buffer (managed by the class). Like this:
var mObj:=TQTXWriter.Create(null); try mObj.writeStr("first-name",edFirstname.text); mobj.writeStr("last-name",edLastName.text); mObj.writeStr("cardID",edVisa.text); CallCardLookup(mObj.Deserialize, procedure () begin showmessage("Visa card is valid"); end); finally mObj.free; end;
And TQTXReader does the exact same, but in reverse. The constructor can take a variant containing the information you want to read (stored with TQTXWriter) and extract info in the same way.
Practical uses
Loads! You can use it to tailor custom messages to be used with the spanking new message-api. That way you don’t have to fiddle with JObject based classes. Serialize() and Deserialize() are the methods for turning the data into a string and back again.
You can use it to avoid strictly typed records, which can be handy – especially for grid designs and/or “flexible” arrays of content. But please remember that Serialize() and Deserialize() are costly in terms of speed.
It’s also perfect to interface with JS libraries which expects name-value pairs in constructors and setup routines.
But word to the wise – if all you need is a one-shot wonder, then TQTXWriter is overkill. In such a case you can get away with an anonymous record:
Fhandle.setupJS( record mouse := "yes"; startX := 100; startY := 100; end);
You must be logged in to post a comment.