Recent

Author Topic: Breakout clone with raylib (ray4laz)  (Read 757 times)

Nimbus

  • New Member
  • *
  • Posts: 43
Breakout clone with raylib (ray4laz)
« on: April 26, 2025, 06:57:51 pm »
Hi guys,

Recently I thought I'd have a look into raylib, so then set and wrote this breakout clone. Which turned to be better experience than I expected (I didn't really write many games in my life) - so sharing it here.

And of course my respect to @Guva for exellent bindings for raylib via ray4laz package!

Source and executable below:
https://limewire.com/d/J1eZj#hCPudTVUxC

Guva

  • Full Member
  • ***
  • Posts: 177
  • 🌈 ZX-Spectrum !!!
Re: Breakout clone with raylib (ray4laz)
« Reply #1 on: April 26, 2025, 07:27:15 pm »
@Nimbus good job !!! especially gun 8-)

flowCRANE

  • Hero Member
  • *****
  • Posts: 926
Re: Breakout clone with raylib (ray4laz)
« Reply #2 on: April 26, 2025, 09:33:44 pm »
Cute little game, I like it! 8)



But I have one fundamental problem with this game — why does the game process eat up all the available CPU core time, since VSync is enabled (I checked it with FRAPS)? See the attachment, this game shouldn't use more than a few percent of CPU time, but it does use almost 30% — this is a pure waste of resources and electricity.
« Last Edit: April 26, 2025, 09:47:54 pm by flowCRANE »
Lazarus 4.0 with FPC 3.2.2, Windows 10 — all 64-bit

Working solo on a retro-style action/adventure game (pixel art), programming the engine from scratch, using Free Pascal and SDL3.

Nimbus

  • New Member
  • *
  • Posts: 43
Re: Breakout clone with raylib (ray4laz)
« Reply #3 on: April 26, 2025, 10:00:34 pm »
Cute little game, I like it! 8)



But I have one fundamental problem with this game — why does the game process eat up all the available CPU core time, since VSync is enabled (I checked it with FRAPS)? See the attachment, this game shouldn't use more than a few percent of CPU time, but it does use almost 30% — this is a pure waste of resources and electricity.

Well, honestly that I don't know. It runs at 8% core on my linux machine from 2010s when 60HZ/vsync, and like 2000 FPS when uncapped. I didn't make many measurements in Windows though because I don't use it much.

The vsync and frame limits can be adjusted in raybrick.cfg (created on the first run in the user configs directory, which is something like 'C:\Users\Usrname\AppData\Local\raybrick\' on Windows, I believe). By default it will use vsync and limit to 144 FPS if that doesn't work somehow - which seems to work well on my linux and windows boxes, though spotted inconsistencies under macos, but that all depends how the program, raylib, and the gpu drivers all work together, through all levels of abstractions.

Again, I'm really no game developer in any way, this wasn't written for a performance contest, just an exercise on interacting with raylib.
Apologies if it offended or wasted anyone's resources in vain, I assure you it not on purpose.
« Last Edit: April 26, 2025, 10:10:53 pm by Nimbus »

flowCRANE

  • Hero Member
  • *****
  • Posts: 926
Re: Breakout clone with raylib (ray4laz)
« Reply #4 on: April 26, 2025, 10:15:06 pm »
I don't know raylib (I use SDL3 for my games), but maybe the source code of this game will give me some hints.

Edit: Okay, I played around with the settings file and it turns out that the game eats up CPU time when the number of FPS in the configuration file is higher than the refresh rate of the display. I have a 60Hz monitor and if the target_fps key is no higher than 60, the game uses a few percent of CPU time. However, if it is higher than the monitor frequency, even by one frame (i.e. if I set target_fps to 61 or higher), the game eats up 20-30% of CPU time, even if VSync is enabled.

It turns out that if the monitor refresh rate is lower than target_fps, raylib uses spinlocks (or similar "hungry" delays) and therefore uses such a large amount of CPU time (this is very bad). It would be good if the game simply reads the monitor refresh rate during startup and uses it to set the number of frames per second.

But that's a detail. Nevermind, good job anyway! 8)



BTW: Arkanoid for the NES console was programmed to be played with a standard gamepad, but you could buy a special paddle controller (with a knob), which was much more convenient to play with, because you could move the paddle much faster than with the D-Pad (as fast as you can turn the knob).

Therefore, if you want to tinker with the code a bit more, I highly recommend adding the ability to move the paddle with the mouse. But remember, if you add mouse control, don't forget to limit the mouse cursor movement to the window area (so that the cursor can't move outside the window).
« Last Edit: April 26, 2025, 10:55:07 pm by flowCRANE »
Lazarus 4.0 with FPC 3.2.2, Windows 10 — all 64-bit

Working solo on a retro-style action/adventure game (pixel art), programming the engine from scratch, using Free Pascal and SDL3.

Nimbus

  • New Member
  • *
  • Posts: 43
Re: Breakout clone with raylib (ray4laz)
« Reply #5 on: April 26, 2025, 10:52:09 pm »
It turns out that if the monitor refresh rate is lower than target_fps, raylib uses spinlocks (or similar "hungy" delays) and therefore uses such a large amount of CPU time (this is very bad). It would be good if the game simply reads the monitor refresh rate during startup and uses it to set the number of frames per second.;.

Good spot, thanks for pointing it out

Quote
Therefore, if you want to tinker with the code a bit more, I highly recommend adding the ability to move the paddle with the mouse. But remember, if you add mouse control, don't forget to limit the mouse cursor movement to the window area (so that the cursor can't move outside the window).

Thanks, yeah I left it out in the beginning as thought it would render the game impossible with laptop touchpads.
Probably makes sense to add as an option.

d2010

  • Full Member
  • ***
  • Posts: 161
Re: Breakout clone with raylib (ray4laz)
« Reply #6 on: April 27, 2025, 04:19:35 am »
Hi guys,
Recently I thought I'd have a look into raylib, so then set and wrote this breakout clone. Which turned to be better experience than I expected (I didn't really write many games in my life) - so sharing it here.
And of course my respect to @Guva for exellent bindings for raylib via ray4laz package!
Source and executable below:
https://limewire.com/d/J1eZj#hCPudTVUxC
You search other options, in these videos via youtube.com
https://youtu.be/vK9S8nbjrHc?t=104
https://youtu.be/B39Qw7k9xMs

Guva

  • Full Member
  • ***
  • Posts: 177
  • 🌈 ZX-Spectrum !!!
Re: Breakout clone with raylib (ray4laz)
« Reply #7 on: April 27, 2025, 06:19:10 am »
Hi guys,
Recently I thought I'd have a look into raylib, so then set and wrote this breakout clone. Which turned to be better experience than I expected (I didn't really write many games in my life) - so sharing it here.
And of course my respect to @Guva for exellent bindings for raylib via ray4laz package!
Source and executable below:
https://limewire.com/d/J1eZj#hCPudTVUxC
You search other options, in these videos via youtube.com
https://youtu.be/vK9S8nbjrHc?t=104
https://youtu.be/B39Qw7k9xMs

Well, if you already use shaders, then you can add one to the background, and it shifts along the x coordinate in a place with the platform.

Code: Pascal  [Select][+][-]
  1. program universewithinshader;
  2.  
  3. uses
  4.   raylib, math;
  5.  
  6. const
  7.   SCREEN_WIDTH = 800;
  8.   SCREEN_HEIGHT = 600;
  9.  
  10. var
  11.   Shader: TShader;
  12.   Target: TRenderTexture2D;
  13.   IResolutionLoc, ITimeLoc, ITimeDeltaLoc, IFrameLoc, IMouseLoc: Integer;
  14.   IResolution: array [0..1] of Single;
  15.   IMouse: array [0..3] of Single;
  16.   ITime, PrevTime, ITimeDelta: Single;
  17.   IFrame: Integer;
  18.   MousePos: TVector2;
  19.  
  20. begin
  21.   // Инициализация окна
  22.   InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, 'The Universe Within Shader in Raylib (Pascal)');
  23.  
  24.   // Загрузка шейдера (предполагается, что файл шейдера лежит рядом с исполняемым файлом)
  25.   Shader := LoadShader(nil, 'the_universe_within.fs');
  26.  
  27.   // Создание текстуры для рендеринга
  28.   Target := LoadRenderTexture(SCREEN_WIDTH, SCREEN_HEIGHT);
  29.  
  30.   // Получение location uniform-переменных
  31.   IResolutionLoc := GetShaderLocation(Shader, 'iResolution');
  32.   ITimeLoc := GetShaderLocation(Shader, 'iTime');
  33.   ITimeDeltaLoc := GetShaderLocation(Shader, 'iTimeDelta');
  34.   IFrameLoc := GetShaderLocation(Shader, 'iFrame');
  35.   IMouseLoc := GetShaderLocation(Shader, 'iMouse');
  36.  
  37.   // Установка начальных значений
  38.   IResolution[0] := SCREEN_WIDTH;
  39.   IResolution[1] := SCREEN_HEIGHT;
  40.   SetShaderValue(Shader, IResolutionLoc, @IResolution, SHADER_UNIFORM_VEC2);
  41.  
  42.   IMouse[0] := 0.0;
  43.   IMouse[1] := 0.0;
  44.   IMouse[2] := 0.0;
  45.   IMouse[3] := 0.0;
  46.   SetShaderValue(Shader, IMouseLoc, @IMouse, SHADER_UNIFORM_VEC4);
  47.  
  48.   IFrame := 0;
  49.   ITime := 0.0;
  50.   PrevTime := 0.0;
  51.  
  52.   SetTargetFPS(60);
  53.  
  54.   // Основной цикл
  55.   while not WindowShouldClose() do
  56.   begin
  57.     // Обновление
  58.     ITime := GetTime();
  59.     ITimeDelta := ITime - PrevTime;
  60.     PrevTime := ITime;
  61.     Inc(IFrame);
  62.  
  63.     MousePos := GetMousePosition();
  64.     IMouse[0] := MousePos.x;
  65.     IMouse[1] := MousePos.y;
  66.     IMouse[2] := GetMouseDelta().x;
  67.     IMouse[3] := GetMouseDelta().y;
  68.  
  69.     // Обновление uniform-переменных
  70.     SetShaderValue(Shader, ITimeLoc, @ITime, SHADER_UNIFORM_FLOAT);
  71.     SetShaderValue(Shader, ITimeDeltaLoc, @ITimeDelta, SHADER_UNIFORM_FLOAT);
  72.     SetShaderValue(Shader, IFrameLoc, @IFrame, SHADER_UNIFORM_INT);
  73.     SetShaderValue(Shader, IMouseLoc, @IMouse, SHADER_UNIFORM_VEC4);
  74.  
  75.     // Рендеринг
  76.     BeginDrawing();
  77.       ClearBackground(BLACK);
  78.  
  79.       BeginShaderMode(Shader);
  80.         // Рисуем прямоугольник на весь экран с шейдером
  81.         DrawRectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, WHITE);
  82.       EndShaderMode();
  83.  
  84.       // Отображение FPS
  85.       DrawFPS(10, 10);
  86.     EndDrawing();
  87.   end;
  88.  
  89.   // Очистка
  90.   UnloadShader(Shader);
  91.   UnloadRenderTexture(Target);
  92.   CloseWindow();
  93. end.
  94.  

the_universe_within.fs
Code: C  [Select][+][-]
  1. #version 300
  2.  
  3. precision highp float;
  4.  
  5. uniform vec2 iResolution;
  6. uniform float iTime;
  7. uniform float iTimeDelta;
  8. uniform int iFrame;
  9. uniform vec4 iMouse;
  10. out vec4 shadertoy_outcolor;
  11.  
  12. // The Universe Within - by Martijn Steinrucken aka BigWings 2018
  13. // Email:countfrolic@gmail.com Twitter:@The_ArtOfCode
  14. // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
  15.  
  16. // After listening to an interview with Michael Pollan on the Joe Rogan
  17. // podcast I got interested in mystic experiences that people seem to
  18. // have when using certain psycoactive substances.
  19. //
  20. // For best results, watch fullscreen, with music, in a dark room.
  21. //
  22. // I had an unused 'blockchain effect' lying around and used it as
  23. // a base for this effect. Uncomment the SIMPLE define to see where
  24. // this came from.
  25. //
  26. // Use the mouse to get some 3d parallax.
  27.  
  28. // Music - Terrence McKenna Mashup - Jason Burruss Remixes
  29. // https://soundcloud.com/jason-burruss-remixes/terrence-mckenna-mashup
  30. //
  31. // YouTube video of this effect:
  32. // https://youtu.be/GAhu4ngQa48
  33. //
  34. // YouTube Tutorial for this effect:
  35. // https://youtu.be/3CycKKJiwis
  36.  
  37.  
  38. #define S(a, b, t) smoothstep(a, b, t)
  39. #define NUM_LAYERS 4.
  40.  
  41. //#define SIMPLE
  42.  
  43.  
  44. float N21(vec2 p) {
  45.         vec3 a = fract(vec3(p.xyx) * vec3(213.897, 653.453, 253.098));
  46.     a += dot(a, a.yzx + 79.76);
  47.     return fract((a.x + a.y) * a.z);
  48. }
  49.  
  50. vec2 GetPos(vec2 id, vec2 offs, float t) {
  51.     float n = N21(id+offs);
  52.     float n1 = fract(n*10.);
  53.     float n2 = fract(n*100.);
  54.     float a = t+n;
  55.     return offs + vec2(sin(a*n1), cos(a*n2))*.4;
  56. }
  57.  
  58. float GetT(vec2 ro, vec2 rd, vec2 p) {
  59.         return dot(p-ro, rd);
  60. }
  61.  
  62. float LineDist(vec3 a, vec3 b, vec3 p) {
  63.         return length(cross(b-a, p-a))/length(p-a);
  64. }
  65.  
  66. float df_line( in vec2 a, in vec2 b, in vec2 p)
  67. {
  68.     vec2 pa = p - a, ba = b - a;
  69.         float h = clamp(dot(pa,ba) / dot(ba,ba), 0., 1.);      
  70.         return length(pa - ba * h);
  71. }
  72.  
  73. float line(vec2 a, vec2 b, vec2 uv) {
  74.     float r1 = .04;
  75.     float r2 = .01;
  76.    
  77.     float d = df_line(a, b, uv);
  78.     float d2 = length(a-b);
  79.     float fade = S(1.5, .5, d2);
  80.    
  81.     fade += S(.05, .02, abs(d2-.75));
  82.     return S(r1, r2, d)*fade;
  83. }
  84.  
  85. float NetLayer(vec2 st, float n, float t) {
  86.     vec2 id = floor(st)+n;
  87.  
  88.     st = fract(st)-.5;
  89.    
  90.     vec2 p[9];
  91.     int i=0;
  92.     for(float y=-1.; y<=1.; y++) {
  93.         for(float x=-1.; x<=1.; x++) {
  94.             p[i++] = GetPos(id, vec2(x,y), t);
  95.         }
  96.     }
  97.    
  98.     float m = 0.;
  99.     float sparkle = 0.;
  100.    
  101.     for(int i=0; i<9; i++) {
  102.         m += line(p[4], p[i], st);
  103.  
  104.         float d = length(st-p[i]);
  105.  
  106.         float s = (.005/(d*d));
  107.         s *= S(1., .7, d);
  108.         float pulse = sin((fract(p[i].x)+fract(p[i].y)+t)*5.)*.4+.6;
  109.         pulse = pow(pulse, 20.);
  110.  
  111.         s *= pulse;
  112.         sparkle += s;
  113.     }
  114.    
  115.     m += line(p[1], p[3], st);
  116.         m += line(p[1], p[5], st);
  117.     m += line(p[7], p[5], st);
  118.     m += line(p[7], p[3], st);
  119.    
  120.     float sPhase = (sin(t+n)+sin(t*.1))*.25+.5;
  121.     sPhase += pow(sin(t*.1)*.5+.5, 50.)*5.;
  122.     m += sparkle*sPhase;//(*.5+.5);
  123.    
  124.     return m;
  125. }
  126.  
  127. void mainImage( out vec4 fragColor, in vec2 fragCoord )
  128. {
  129.     vec2 uv = (fragCoord-iResolution.xy*.5)/iResolution.y;
  130.         vec2 M = iMouse.xy/iResolution.xy-.5;
  131.    
  132.     float t = iTime*.1;
  133.    
  134.     float s = sin(t);
  135.     float c = cos(t);
  136.     mat2 rot = mat2(c, -s, s, c);
  137.     vec2 st = uv*rot;  
  138.         M *= rot*2.;
  139.    
  140.     float m = 0.;
  141.     for(float i=0.; i<1.; i+=1./NUM_LAYERS) {
  142.         float z = fract(t+i);
  143.         float size = mix(15., 1., z);
  144.         float fade = S(0., .6, z)*S(1., .8, z);
  145.        
  146.         m += fade * NetLayer(st*size-M*z, i, iTime);
  147.     }
  148.    
  149.         float fft  = 0.0f;
  150.     float glow = -uv.y*fft*2.;
  151.    
  152.     vec3 baseCol = vec3(s, cos(t*.4), -sin(t*.24))*.4+.6;
  153.     vec3 col = baseCol*m;
  154.     col += baseCol*glow;
  155.    
  156.     #ifdef SIMPLE
  157.     uv *= 10.;
  158.     col = vec3(1)*NetLayer(uv, 0., iTime);
  159.     uv = fract(uv);
  160.     //if(uv.x>.98 || uv.y>.98) col += 1.;
  161.     #else
  162.     col *= 1.-dot(uv,uv);
  163.     t = mod(iTime, 230.);
  164.     col *= S(0., 20., t)*S(224., 200., t);
  165.     #endif
  166.    
  167.     fragColor = vec4(col,1);
  168. }
  169. void main()
  170. {
  171.         mainImage(shadertoy_outcolor, gl_FragCoord.xy);
  172. }
  173.  


TBMan

  • Full Member
  • ***
  • Posts: 134
Re: Breakout clone with raylib (ray4laz)
« Reply #8 on: May 10, 2025, 07:15:44 pm »
Nice looking graphics!

I had done a quick and dirty version using the ball dynamics on a pinball game project I was working on. Fun to fool around with. This is with just using ptcgraph.

https://www.youtube.com/watch?v=YCk49ERJPc0

d2010

  • Full Member
  • ***
  • Posts: 161
Re: Breakout clone with raylib (ray4laz)
« Reply #9 on: May 10, 2025, 08:15:46 pm »
Hi guys,
Recently I thought I'd have a look into raylib, so then set and wrote this breakout clone. Which turned to be better experience than I expected (I didn't really write many games in my life) - so sharing it here.
The Music.ogg  not hear, Why is crash ? Do you hear the music.ogg?
« Last Edit: May 12, 2025, 01:02:39 am by d2010 »

 

TinyPortal © 2005-2018