MaxCircles
Smart Mobile Studio visual effect by Felix Thompson: Y13 Age ~18
Introduction
Felix implements his original idea skilfully to create a pleasing visual effect. He comments the code so thoroughly that we feel no further explanation is necessary. See also the use of much of the code in the form-based Compendium.
The code follows the graphic in action. Refresh the screen for a different output.
If MaxCircles does not run in your current browser, please try another (such as Chrome). If you see no display at school, the security system might have blocked it. You can try instead this direct link to the program running on its own page.
The Code
Felix developed this code using Version 2.1 of Smart Mobile Studio. See the last section on this page for code that compiles with Version 3.0.
unit MaxCircles; { Copyright (c) 2014 Felix Thompson Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License, as described at http://www.apache.org/licenses/ and http://www.pp4s.co.uk/licenses/ } interface uses W3System, W3Components, W3Application, W3Game, W3GameApp, W3Graphics; type TApplication = class(TW3CustomGameApplication) protected procedure ApplicationStarting; override; procedure ApplicationClosing; override; procedure PaintView(Canvas: TW3Canvas); override; end; implementation var Colour1, Colour2, Colour3, F1, F2, F3, CircleCount, W, HW, TestR : Integer; PastX, PastY, PastR : Array [1..100000] of Integer; CurX, CurY, CurR : Integer; MaxX, MaxY, MaxR : Integer; Count, Count2 : Integer; procedure TApplication.ApplicationStarting; begin inherited; Randomize; GameView.Delay := 10; GameView.StartSession(True); //The width is set and the W := 300; //half-width is calculated HW := W DIV 2; //as they are both used repeatedly GameView.Width := W; GameView.Height := W; end; procedure TApplication.ApplicationClosing; begin GameView.EndSession; inherited; end; procedure TApplication.PaintView(Canvas: TW3Canvas); var Count, Count2, Count3 : Integer; begin if CircleCount = 0 then begin //The screen is drawn a specific Canvas.FillStyle := 'Black'; //colour when the program starts. Canvas.FillRect(0, 0, W, W); end; Colour1 := RandomInt(175); Colour2 := RandomInt(100) + 156; //The colours are biased to be Colour3 := RandomInt(100) + 100; //certain hues. CurX := RandomInt(W + 1); //The first circle is plotted CurY := RandomInt(W + 1); //randomly. CurR := HW - ABS(HW - CurX); if CurR > (HW - ABS(HW - CurY)) then //This makes the radius such that CurR := HW - ABS(HW - CurY); //it touches the closest edge. MaxR := 0; if CircleCount <> 0 then begin for Count := 1 to W do begin CurX := Count; for Count2 := 1 to W do begin //This scans through each pixel CurY := Count2; //and determines the maximum size //of a circle plotted at that point CurR := HW - ABS(HW - CurX); if CurR > (HW - ABS(HW - CurY)) then CurR := HW-ABS(HW - CurY); //Here it finds the radius that makes for Count3 := 1 to CircleCount do //it touch the edge of another circle. begin if CurR > (Sqrt(Sqr(CurX - PastX[Count3]) + Sqr(CurY - PastY[Count3])) - PastR[Count3]) then CurR := Round(Sqrt(Sqr(CurX - PastX[Count3]) + Sqr(CurY - PastY[Count3])) - PastR[Count3]); if CurR <= 0 then Break; //If the pixel is inside a circle it is end; //discounted if CurR > MaxR then begin //It checks if it is the largest possible MaxX := CurX; //circle drawable. If it is it saves the point MaxY := CurY; MaxR := CurR; end; end; end; CurX := MaxX; //The centre and radius of the largest CurY := MaxY; //circle is loaded for use. CurR := MaxR; end; if CurR <> 0 then //Checks that the circle has size. begin Canvas.FillStyle := 'rgb('+IntToStr(Colour1)+ ',' + IntToStr(Colour2) + ',' + IntToStr(Colour3) + ')'; Canvas.BeginPath; //Draw the circle. Canvas.Ellipse(CurX - CurR, CurY - CurR, CurX + CurR, CurY + CurR); Canvas.ClosePath; Canvas.Fill; Inc(CircleCount); //The location and size is saved PastX[CircleCount] := CurX; //so the circles will not overlap. PastY[CircleCount] := CurY; PastR[CircleCount] := CurR; end; end; end.
Code that compiles with Version 3.0 of Smart Mobile Studio
unit MaxCircles; { Copyright (c) 2014 Felix Thompson Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License, as described at http://www.apache.org/licenses/ and http://www.pp4s.co.uk/licenses/ } interface uses SmartCL.System, SmartCL.Components, SmartCL.Application, SmartCL.Game, SmartCL.GameApp, SmartCL.Graphics; type TCanvasProject = class(TW3CustomGameApplication) protected procedure ApplicationStarting; override; procedure ApplicationClosing; override; procedure PaintView(Canvas: TW3Canvas); override; end; implementation var Colour1, Colour2, Colour3, F1, F2, F3, CircleCount, W, HW, TestR : Integer; PastX, PastY, PastR : Array [1..100000] of Integer; CurX, CurY, CurR : Integer; MaxX, MaxY, MaxR : Integer; Count, Count2 : Integer; procedure TCanvasProject.ApplicationStarting; begin inherited; Randomize; GameView.Delay := 10; GameView.StartSession(True); //The width is set and the W := 300; //half-width is calculated HW := W DIV 2; //as they are both used repeatedly GameView.Width := W; GameView.Height := W; end; procedure TCanvasProject.ApplicationClosing; begin GameView.EndSession; inherited; end; procedure TCanvasProject.PaintView(Canvas: TW3Canvas); var Count, Count2, Count3 : Integer; begin if CircleCount = 0 then begin //The screen is drawn a specific Canvas.FillStyle := 'Black'; //colour when the program starts. Canvas.FillRect(0, 0, W, W); end; Colour1 := RandomInt(175); Colour2 := RandomInt(100) + 156; //The colours are biased to be Colour3 := RandomInt(100) + 100; //certain hues. CurX := RandomInt(W + 1); //The first circle is plotted CurY := RandomInt(W + 1); //randomly. CurR := HW - ABS(HW - CurX); if CurR > (HW - ABS(HW - CurY)) then //This makes the radius such that CurR := HW - ABS(HW - CurY); //it touches the closest edge. MaxR := 0; if CircleCount <> 0 then begin for Count := 1 to W do begin CurX := Count; for Count2 := 1 to W do begin //This scans through each pixel CurY := Count2; //and determines the maximum size //of a circle plotted at that point CurR := HW - ABS(HW - CurX); if CurR > (HW - ABS(HW - CurY)) then CurR := HW-ABS(HW - CurY); //Here it finds the radius that makes for Count3 := 1 to CircleCount do //it touch the edge of another circle. begin if CurR > (Sqrt(Sqr(CurX - PastX[Count3]) + Sqr(CurY - PastY[Count3])) - PastR[Count3]) then CurR := Round(Sqrt(Sqr(CurX - PastX[Count3]) + Sqr(CurY - PastY[Count3])) - PastR[Count3]); if CurR <= 0 then Break; //If the pixel is inside a circle it is end; //discounted if CurR > MaxR then begin //It checks if it is the largest possible MaxX := CurX; //circle drawable. If it is it saves the point MaxY := CurY; MaxR := CurR; end; end; end; CurX := MaxX; //The centre and radius of the largest CurY := MaxY; //circle is loaded for use. CurR := MaxR; end; if CurR <> 0 then //Checks that the circle has size. begin Canvas.FillStyle := 'rgb('+IntToStr(Colour1)+ ',' + IntToStr(Colour2) + ',' + IntToStr(Colour3) + ')'; Canvas.BeginPath; //Draw the circle. Canvas.Ellipse(CurX - CurR, CurY - CurR, CurX + CurR, CurY + CurR); Canvas.ClosePath; Canvas.Fill; Inc(CircleCount); //The location and size is saved PastX[CircleCount] := CurX; //so the circles will not overlap. PastY[CircleCount] := CurY; PastR[CircleCount] := CurR; end; end; end.