Posts: 366
Threads: 42
Joined: Nov 2023
Reputation:
3
I was going through some old drives and noticed that I have a tendency to concentrate on "old" games... Cannot figure out why... lol
I found an old text-based Moon Lander from the late 70's... and got to thinking... (Ok. Stop laughing...) I have seen "many" versions of this game for most machines that I have owned in the past... For nostalgia, I was thinking of trying my hand at an N7 version... Which got me to thinking again... (Really. Still laughing? *sigh*)
I am pretty clear on the game elements... except for one... Collision...
Oh. I know how to do simple AABB and Circular collisions but, when it comes to colliding with the "landscape", I am at a loss as to finding an efficient method of detection.
Most of my "programming" has been using Basic. Unless the "Basic" has a sprite collision system built in - detecting collision has been either by AABB, Circular or Colour detection. The latter would work for the "landscape" but it is SO inefficient... I cannot use AABB or Circular as the landscape is irregularly shaped... Oh. text was SO much easier... lol
I have always enjoyed the "old stuff"... It is probably because of the way I think... (Nope. I am not going to say it...)
Any suggestions, or constructive criticisms, are always appreciated.
J
(PS: I hope that everyone will have a great and safe Easter break...)
Logic is the beginning of wisdom.
Posts: 75
Threads: 4
Joined: Dec 2023
Reputation:
4
An interesting question. Can I ask how you would be drawing the landscape? Better still, could you show an example of it in N7?
Posts: 366
Threads: 42
Joined: Nov 2023
Reputation:
3
As you have rightly asked, "an interesting question"... I suppose I could start with the most basic (no pun intended) and start with a completely flat landscape. That would be very achievable as it would require only a simple AABB (rectangle / rectangle) collision... But nobody wants a completely flat landing, right? Where would be the difficulty?
Warning. My experience in creating landscapes is based on very old school styles... lol
I have seen many "types" of landscapes drawn... Simple screen-wide set of vertical lines, drawn from the base of the screen to random heights... Similar using vertical rectangles in stead of lines... A single segmented line drawn across the screen with "flat spots" for landing targets... Crafted "png" file of landscape with a "launching" and "landing" pads post-drawn by the program.
The type I would like to use is the "png" option. I would like to use images created for a "Scratch" project from way back. I will try to find an image and attach it... As I am still in the "concept" stage, I have not as yet written any N7 code for the other methods...
J
Logic is the beginning of wisdom.
Posts: 75
Threads: 4
Joined: Dec 2023
Reputation:
4
Great - this is a nice challenge. I have a couple of ideas that I will test today. In the meantime, it would be very interesting to see anyone else's solutions.....
Posts: 75
Threads: 4
Joined: Dec 2023
Reputation:
4
03-29-2024, 09:00 AM
(This post was last modified: 03-29-2024, 09:46 AM by kevin.
Edit Reason: Add the control keys
)
(03-29-2024, 07:40 AM)kevin Wrote: Great - this is a nice challenge. I have a couple of ideas that I will test today. In the meantime, it would be very interesting to see anyone else's solutions.....
Hi Johnno, my first attempt is attached at the bottom of this post. And here is the code:
Code: visible screen_w = 640,screen_h = 480
'Open a window
set window "Landscape collision",screen_w,screen_h
'enable double buffering
set redraw off
visible bg_image = loadimage("bg.png")
visible points = [];initiate_points()
'visible spaceship = []
visible spaceship = [x:screen_w / 2,y:130,w:32,h:96,dx:0,dy:0]
############ to calculate FPS ##########################
visible framecount,lasttime = 999,fps,frametime = 0,starttime = 0,endtime = 0,min_fps = 99999,max_fps = 0
##########################################################
##############################################################################################
####################################### GAME LOOP #########################################
##############################################################################################
do
### for FPS calc #########
framecount = framecount + 1
starttime = clock()
###########################
spaceship.dx = 0;spaceship.dy = 0
if keydown(KEY_LEFT) then spaceship.dx = -1
if keydown(KEY_RIGHT) then spaceship.dx = 1
if keydown(KEY_UP) then spaceship.dy = -2
if keydown(KEY_DOWN) then spaceship.dy = 2
move_and_check_collision()
'gravity
spaceship.y = spaceship.y + 1
'clear the screen
set color 255,255,255
cls
draw image bg_image,0,0
set color 0,0,255
draw rect spaceship.x,spaceship.y,spaceship.w,spaceship.h,1
set color 0,0,0
set caret 30,10
set justification left
write "mouse = " + mousex() + " / " + mousey();wln
write "FPS = " + str(fps);wln
write "MIN_FPS = " + str(min_fps);wln
write "MAX_FPS = " + str(max_fps);wln
write "sizeof(points) " + sizeof(points);wln
'copy back buffer to the screen
redraw
col2 = pixel(2,screen_h - 10)
'cap FPS to 60
fwait 1000
####### FPS calc ############################
endtime = clock()
frametime = frametime + endtime - starttime
if frametime > 1000 # 1 second
fps = framecount
framecount = 0
frametime = 0
if fps < min_fps then min_fps = fps
if fps > max_fps then max_fps = fps
endif
################################################
until keydown(KEY_ESCAPE)
#########################################################################################
################################# FUNCTIONS ###########################################
#########################################################################################
function initiate_points()
x = 0
while x < screen_w - 1
set color 0,0,0
cls
set color 255,255,255
draw image bg_image,0,0
for x = 0 to screen_w - 1
for y = screen_h - 1 to 0 step - 1
col = pixel(x,y)
if col[0] = 255 and col[1] = 255 and col[2] = 255
points[sizeof(points)] = [x,y]
break
endif
next
next
redraw
wend
endfunc
'==========================================================
function move_and_check_collision()
spaceship.x = spaceship.x + spaceship.dx
spaceship.y = spaceship.y + spaceship.dy
if spaceship.x < 0 then spaceship.x = 0
if spaceship.x + spaceship.w > screen_w then spaceship.x = screen_w - spaceship.w
for x = spaceship.x to spaceship.x + spaceship.w
if x < screen_w
if points[x][1] < spaceship.y + spaceship.h
pln"collision"
spaceship.y = points[x][1] - spaceship.h
endif
endif
next
pln ""
endfunc
'==========================================================
I've used a different background image, as I wanted to simplify it - this code needs a background where for each pixel across the screen, the top of the landscape only appears once.
You can move the "spaceship" with the arrow keys.
What the code does:
- creates a table of 640 elements (screen width) which records the y value of the top of the landscape for each of the 640 x values across the screen - it does this by checking for the colour of the "sky". As this table is created before the main program runs, it does not slow it down at all.
- when the main program is running, there is a collision check for the spacecraft against the landscape. It only looks at 32 elements (the width of the spaceship) of the table created above on each cycle, so should be reasonably efficient.
I'm getting comfortably over 200 fps on my ancient laptop. Please let me know what you think, and if a different approach may be needed?
All the best - Kevin.
landscape collision.zip (Size: 5.61 KB / Downloads: 4)
Posts: 366
Threads: 42
Joined: Nov 2023
Reputation:
3
03-29-2024, 10:57 AM
(This post was last modified: 03-29-2024, 11:33 AM by johnno56.)
Well... I must say that using "pixel()" to check for collision run a whole lot faster than I thought it would... Now, you have to remember, the kind of machines that I used "back then" were dinosaurs... 8 bit; 64k ram; 4mhz cpu... I would check for just two points of contact. Both bottom corners would check if both corners were touching the landing pad colour otherwise, boom! At 4mhz, checking two points, was a real workout... lol
Your test ran SO fast that the "ship" would jump around like a jack rabbit... LOL
In the morning I will see if I can use the sample level image and apply the reverse... If the ship is NOT touching the "top layer" of the ground, keep falling or control the ship... maybe...
Appreciate your assistance... Cool...
Logic is the beginning of wisdom.
Posts: 75
Threads: 4
Joined: Dec 2023
Reputation:
4
03-29-2024, 11:12 AM
(This post was last modified: 03-29-2024, 11:26 AM by kevin.)
Yes, it's running fast because I'm not restricting the speed with the fwait function - it's currently set at 1000 so that I could check the FPS properly - if you change it to 60 it will run more sensibly. And the pixel () function does not slow the program down at all because it's only used once ( before the main program runs). I too have found that if you use it every cycle, you do need to be aware of potential slow downs. Enjoy your evening..... Kevin.
Actually, I just spotted line 57:
col2 = pixel(2,screen_h - 10)
This line is totaly unnecessary, and is left over from some testing I did earlier - if you remove it, or comment it out, it will increase speed marginally.
Posts: 361
Threads: 42
Joined: Nov 2023
Reputation:
3
03-29-2024, 04:04 PM
(This post was last modified: 03-29-2024, 04:07 PM by Marcus.)
I just briefed through your discussion. 'pixel' can be quite slow in n7. It "spawns" tables (arrays) that the garbage collector has to deal with. I have already thought about letting 'pixel' reuse and return the same array every time it's called, but that might break some code that people have already written ... hm. Maybe a better solution would be to add something like 'pixeli' from n6 that returns the color as a single integer? The "only" problem with that is that n7 doesn't have integers, just doubles, but ... maybe it will still work since the integer range of a 64 bit double is that of a 32 bit integer. Me have to think
Posts: 366
Threads: 42
Joined: Nov 2023
Reputation:
3
Per chance that I may have opened, what is commonly called, a can of worms? Admittedly, I am aware of the inefficiency of using "pixel()' for collision detection, but was stunned to see it run so quickly. Kind of like the "Swan" scenario... From the "outside", a swan seems to glide effortlessly across the pond, but underneath the legs are working furiously....
I am going to have to re-think this collision issue... Are we familiar with the theory of Occam's Razor? "Occam's razor states that the simplest explanation is preferable to one that is more complex. Simple theories are easier to verify. Simple solutions are easier to execute."
I always tend to fall back to the simplest collision method, Axial Aligned Bounding Box. What if the landscape was made up of rectangles of various sizes and assign each rectangle its own "zone"? I am not sure if the Zone command has been used like that before, but surely, it has to be more efficient than checking collisions by using "pixel()"? It would make for a "boxy" looking landscape, but if the overall "style" of the game was more "minimalist", say monochromatic, it might work.
I would like to use the phrase, "thinking outside the box", but 'that' would be too corny, right? Now where did I put my paper and crayons... This will either be fun or a flop... I would prefer fun... lol
Logic is the beginning of wisdom.
Posts: 361
Threads: 42
Joined: Nov 2023
Reputation:
3
I usually don't mind using pixel information. In that Mario Kart clone I wrote (it's seen in some video on my youtube channel) I actually used pixel tests to see on which type of ground the cars were at. I had an invisible image, a small version of the entire map, with just three different colors on it: one for the road, one for grass and one for solid obstacles. So I scaled down a car's position to its equivalent on the "collision image". If the car was on a road pixel everything was fine. If it was on a grass pixel, lower the speed. On a solid obstacle pixel, bounce the car away in the opposite direction.
|