Jump to content
IGNORED

Open world generator musings


Captain Spazer

Recommended Posts

I'm having a hard time thinking this setup out. My idea is this: There is a world where each screen is a place on a grid, and there is a variable that randomly picks a playfield for each of those screens in order to build the world.

 

At the moment, the best I can think up in terms of a setup is having a variable for each possible room on the grid, and a variable that picks out a playfield for that room, so when the player goes to that room on that grid the roompicker variable picks a playfield, then I would need another variable I am guessing that keeps track of whether the room has been visited before so the screen remains what was picked the first time the player enters the room, but it is very variable heavy, and I have yet to figure out how the game will remember if the rooms have been visited or not.

 dim has_room_been_visited.s
 dim roompicker.c
 dim grid_room1.d
 dim grid_room2.e
 dim grid_room3.f
 dim grid_room4.g
 dim grid_room5.h
 dim grid_room6.i
 dim grid_room7.j
 dim grid_room8.k
 dim grid_room9.l
 dim grid_room10.m
 dim grid_room11.n
 dim grid_room12.o
 dim grid_room13.p
 dim grid_room14.q
 dim grid_room15.r

I have another idea too that is a little less heavy on variables: Each time the player leaves the current room, the roompicker picks a playfield, and adds 1 to the add_new_room variable and subtracts 1 to the rooms_left_to_place variable. When the rooms_left_to_place variable reaches 0, no new rooms are placed. Still, need a way to remember if room has been visited or not so it remains static and does not randomize again.

 dim roompicker.a
 dim add_new_room.b
 dim rooms_left_to_place.c

 

Any thoughts, insights or ideas?

  • Like 2
Link to comment
Share on other sites

Here is a functional tech demo code, when moving to the right, the game chooses between 4 different rooms, and the rooms remain static throughout the whole game. And it has a pretty good collision detection too. There are 3 rooms total you can move in by going to the right, head back to a previous room by going left.

 

I am sure it can be optimized to save memory, as it's currently setup, it will require a lot of memory for a sizable map.

 

Is there a way to have the screens share the playfield data so the game can pick from a pool of rooms without duplicating the playfields for each screen?
 

 rem Generated 06/06/2021 18:41:05 by Visual bB Version 1.0.0.554
 rem **********************************
 rem *<filename>                      *
 rem *<description>                   *
 rem *<author>                        *
 rem *<contact info>                  *
 rem *<license>                       *
 rem **********************************

 set kernel_option no_blank_lines

 dim rand16 = z
 dim current_room_number = c
   dim p0_x = d
   dim p0_y = e

 dim room11_generator = f
 dim room12_generator = g
 dim room13_generator = h
game_setup

 ballx = 80 : bally = 50
 current_room_number = 10
 room11_generator = (rand&3) + 1
 room12_generator = (rand&3) + 1
 room13_generator = (rand&3) + 1
setup_map

main

 if current_room_number = 10 then playfield:
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
 X...............................
 X...............................
 X...............................
 X...............................
 X...............................
 X...............................
 X...............................
 X...............................
 X...............................
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
end

 rem ROOM11 OPTIONS
 if current_room_number = 11 && room11_generator = 1 then playfield:
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ........XXX...........XXX.......
 .........X.............X........
 .........X.............X........
 ........XXX...........XXX.......
 ................................
 ................................
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
end

 if current_room_number = 11 && room11_generator = 2 then playfield:
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
end

 if current_room_number = 11 && room11_generator = 3 then playfield:
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
 ................................
 ................................
 .........XX..........XX.........
 .......XXXXXX......XXXXXX.......
 ......XXXXXXXX....XXXXXXXX......
 .......XXXXXX......XXXXXX.......
 .........XX..........XX.........
 ................................
 ................................
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
end

 if current_room_number = 11 && room11_generator = 4 then playfield:
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
 ....XXXXXXXXX...................
 ....XXXXXXXXX...................
 ....XXXXXXXXX...................
 ...................XXXXXXXXX....
 ...................XXXXXXXXX....
 ...................XXXXXXXXX....
 ....XXXXXXXXX...................
 ....XXXXXXXXX...................
 ....XXXXXXXXX...................
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
end

 rem ROOM12 OPTIONS
 if current_room_number = 12 && room12_generator = 1 then playfield:
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ........XXX...........XXX.......
 .........X.............X........
 .........X.............X........
 ........XXX...........XXX.......
 ................................
 ................................
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
end

 if current_room_number = 12 && room12_generator = 2 then playfield:
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
end

 if current_room_number = 12 && room12_generator = 3 then playfield:
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
 ................................
 ................................
 .........XX..........XX.........
 .......XXXXXX......XXXXXX.......
 ......XXXXXXXX....XXXXXXXX......
 .......XXXXXX......XXXXXX.......
 .........XX..........XX.........
 ................................
 ................................
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
end

 if current_room_number = 12 && room12_generator = 4 then playfield:
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
 ....XXXXXXXXX...................
 ....XXXXXXXXX...................
 ....XXXXXXXXX...................
 ...................XXXXXXXXX....
 ...................XXXXXXXXX....
 ...................XXXXXXXXX....
 ....XXXXXXXXX...................
 ....XXXXXXXXX...................
 ....XXXXXXXXX...................
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
end

 rem ROOM13 OPTIONS
 if current_room_number = 13 && room13_generator = 1 then playfield:
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ........XXX...........XXX.......
 .........X.............X........
 .........X.............X........
 ........XXX...........XXX.......
 ................................
 ................................
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
end

 if current_room_number = 13 && room13_generator = 2 then playfield:
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
end

 if current_room_number = 13 && room13_generator = 3 then playfield:
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
 ................................
 ................................
 .........XX..........XX.........
 .......XXXXXX......XXXXXX.......
 ......XXXXXXXX....XXXXXXXX......
 .......XXXXXX......XXXXXX.......
 .........XX..........XX.........
 ................................
 ................................
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
end

 if current_room_number = 13 && room13_generator = 4 then playfield:
 XXXXXXXXXXXXX......XXXXXXXXXXXXX
 ....XXXXXXXXX...................
 ....XXXXXXXXX...................
 ....XXXXXXXXX...................
 ...................XXXXXXXXX....
 ...................XXXXXXXXX....
 ...................XXXXXXXXX....
 ....XXXXXXXXX...................
 ....XXXXXXXXX...................
 ....XXXXXXXXX...................
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
end

 CTRLPF = $31
 ballheight = 8
 COLUPF=$0E
 COLUBK=$00
 scorecolor = $0E
 rem PLAYER CONTROLS

   p0_x = 0
   if joy0left then p0_x = 255
   if joy0right then p0_x = 1
   ballx = ballx + p0_x

   p0_y = 0
   if joy0up then p0_y = 255
   if joy0down then p0_y = 1
   bally = bally + p0_y


 if ballx > 130 then ballx = 10 : current_room_number = current_room_number + 1 : score = score + 1
 if ballx < 10 then ballx = 130 : current_room_number = current_room_number - 1 : score = score - 1

 if bally > 80 then bally = 10 : current_room_number = current_room_number + 10
 if bally < 10 then bally = 80 : current_room_number = current_room_number - 10

 drawscreen

   if collision(ball,playfield) then gosub knock_player_back
   goto main

knock_player_back
   ballx = ballx - p0_x
   bally = bally - p0_y
   return

 goto main

 

Edited by Captain Spazer
  • Like 1
Link to comment
Share on other sites

This is similar to a problem I've tried to figure out for myself. To get a simple repeating pattern, one can use the rand function, and you can even use an "unrand" function to get the previous number. The sequence of numbers would be the same within the same game, so you would get the same numbers going forward and backwards every time for a consistent world. This could be used e.g. to generate screens for a game like Pitfall where you can move right or left to get to new screens, but not up or down. Using rand and the reverse rand function depending on which direction you are going would get you consistent screens as you traverse the linear world without having to store the screen types in variables.

 

Now, in the case of a grid, it becomes slightly more complicated. Going to new screens on the left and right are covered as described above, but for going up or down, you would run the rand or reverse rand function multiple times, depending on the number of columns. For example, if the world were an 8x8 grid, and the player moved down one screen, the rand function would be run 8 times, or the reverse rand in the case of the player going up one screen. This would be a lot of cycles used, but it might be okay since it would only need to happen for screen changes.

 

If I get a chance, I may try to whip up a proof-of-concept demo to demonstrate this.

Link to comment
Share on other sites

Here's an example that uses rand and unrand as described previously to generate an 8x8 world of 64 screens without having to use variables to track what type of screen is in what position.

 

I also track whether each screen has been visited, and an eye icon shows at the bottom of the screen if the current screen has been previously visited (using the 6lives minikernel to display the icon).

 

Bad graphics aside, I think this is more or less what you were going for?

 

A couple of issues with this version:

  • The screen type at each coordinate will vary from game to game, although it will remain the same throughout the same game. This may or may not be what you want. To make it consistent for every game, you can seed the random number generator with a specific number.
  • If you use the rand function for anything else, it throws off the pattern with the rooms. This can be avoided by using a separate rand function, and a different rand variable that does not conflict with the built-in bB one. I'll update this demo to show how this can be done, as I imagine most games will want to make use of the rand function for more than just generating screens.

Note: Not a WIP game for tracking purposes; just a code demo.

 

openworld.bas

openworld.bas.bin

  • Like 9
Link to comment
Share on other sites

Here's the version with a separate rand function and variable for cases where you would want to use rand for more than just generating screens.

 

If you want the generated screens to be the same between game sessions, then you will want to change this line:

 

    bbrand = rand

Set bbrand to any nonzero number at the beginning of the game to act as a number seed, and have the screen types be consistent from game to game.

 

(No compiled version, since it is functionally the same as the previous demo)

 

openworld-separate-rand.bas

  • Like 5
Link to comment
Share on other sites

  • 2 weeks later...
On 6/8/2021 at 3:29 PM, Karl G said:

Here's the version with a separate rand function and variable for cases where you would want to use rand for more than just generating screens.

 

If you want the generated screens to be the same between game sessions, then you will want to change this line:

 


    bbrand = rand

Set bbrand to any nonzero number at the beginning of the game to act as a number seed, and have the screen types be consistent from game to game.

 

(No compiled version, since it is functionally the same as the previous demo)

 

openworld-separate-rand.bas 7.5 kB · 7 downloads

 

Just double checking. The variable bbrand is just for the rooms and rand works normally for everything else as always, right? If so I can use "dim rand16 = <var>" with normal bB, right? I could also adapt the program to work with the DPC+ kernel.

Link to comment
Share on other sites

3 hours ago, Random Terrain said:

 

Just double checking. The variable bbrand is just for the rooms and rand works normally for everything else as always, right? If so I can use "dim rand16 = <var>" with normal bB, right? I could also adapt the program to work with the DPC+ kernel.

Yes, all of that is correct. For DPC+ you would probably want to find another way of showing the screens that have been visited instead of the 6lives minikernel as well. 

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...
Link to comment
Share on other sites

  • 1 year later...

@Karl G first of all, thanks for your code (and thanks to @Random Terrain for example program).

 

I would like to design a world that always remains the same.

 

Is there a way to make the rooms appear in a defined order?

I don't need to track visited rooms.

 

For example, room#

 

1 2 3 4 5 6

7 8 9 10 11 12

13 14 15 16 17 18

19 20 21 22 23 24

25 26 27 28 29 30

31 32 33 34 35 36

 

Thanks!

Link to comment
Share on other sites

2 hours ago, Philsan said:

@Karl G first of all, thanks for your code (and thanks to @Random Terrain for example program).

 

I would like to design a world that always remains the same.

 

Is there a way to make the rooms appear in a defined order?

I don't need to track visited rooms.

 

For example, room#

 

1 2 3 4 5 6

7 8 9 10 11 12

13 14 15 16 17 18

19 20 21 22 23 24

25 26 27 28 29 30

31 32 33 34 35 36

 

Thanks!

Sure. In that case you can just calculate the room number based on your coordinates in the grid. If you stared out at room 3, 4 the room number would just be 3 + (4 * 6). Since your width isn't a power of two, you would probably want to use a lookup table to get the value instead of actually doing the multiplication. Something like:

 

    CurrentRoom = RoomX + y_values[RoomY]
    
    data y_values
    0, 6, 12, 18, 24, 30
end

 

When you have your room number, you can use it in an index to look up e.g. that room's COLUBK and COLUPF values, or to use in a routine that uses on ... goto with the room number to set the appropriate playfield value for the room in question.

Link to comment
Share on other sites

12 minutes ago, Philsan said:

Thank you very much, unfortunately it's too complicated for my bB skills.

 

Isn't there a seed that makes the rooms appear in order?

 

I would need a modification of Random Terrain's example.

No, I don't think there's a seed that can make the random number routine generate numbers in order like that. Perhaps I'm not understanding what you are trying to do. If you aren't wanting to use a random number generator, then the approach would be to decide for yourself what is in each of those rooms by having data or new playfields set based on the number you assign to the room yourself. No real trick to it other than that, unless I misunderstood what you are trying to do here.

Link to comment
Share on other sites

In Random Terrain's 8x8 example there are 64 rooms

   ;  World limit constants. Change these based on world size.
   ;  The default here is 8 x 8 (64 rooms).
   ;  [The c stands for constant.]
   ;
   const _c_World_Limit_Top = 0
   const _c_World_Limit_Bottom = 7
   const _c_World_Limit_Left = 0
   const _c_World_Limit_Right = 7

 

and the rooms have 32 different shapes

   ;```````````````````````````````````````````````````````````````
   ;  Jumps to the current scene to be displayed.
   ;
   on _CurrentScene goto __s0 __s1 __s2 __s3 __s4 __s5 __s6 __s7 __s8 __s9 __sA __sB __sC __sD __sE __sF __sG __sH __sI __sJ __sK __sL __sM __sN __sO __sP __sQ __sR __sS __sT __sU __sV

 

If you select the same seed, rooms location remains the same.

 

Therefore, to have an 6x6 world with 32 different rooms I think I could change this

   const _c_World_Limit_Top = 0
   const _c_World_Limit_Bottom =5
   const _c_World_Limit_Left = 0
   const _c_World_Limit_Right = 5

 

select a seed

 

and then find out where the following rooms are located in the grid with that seed

   on _CurrentScene goto __s0 __s1 __s2 __s3 __s4 __s5 __s6 __s7 __s8 __s9 __sA __sB __sC __sD __sE __sF __sG __sH __sI __sJ __sK __sL __sM __sN __sO __sP __sQ __sR __sS __sT __sU __sV

 

Link to comment
Share on other sites

I'm a little late to the discussion, but when I've used unrand in the past for playfield generation, a problem I ran into, practically, was that I needed to use rand outside of the playfield generation. You could rand and unrand right away just to get a rand for something else without messing up the consistency of the rand for playfield generation, but then it's not really random, as it may give the same answer each time. Also, with unrand, you can neither use 16bit rand nor the DPC+ kernel.

Edited by Fort Apocalypse
Link to comment
Share on other sites

27 minutes ago, Fort Apocalypse said:

I'm a little late to the discussion, but when I've used unrand in the past for playfield generation, a problem I ran into, practically, was that I needed to use rand outside of the playfield generation. You could rand and unrand right away just to get a rand for something else without messing up the consistency of the rand for playfield generation, but then it's not really random, as it may give the same answer each time. Also, with unrand, you can neither use 16bit rand nor the DPC+ kernel.

 

Before I moved, I was working on a DPC+ version of this example program and it was working fine. It just wasn't very fun yet. I need to work on it some more.

Link to comment
Share on other sites

6 hours ago, Random Terrain said:

 

Before I moved, I was working on a DPC+ version of this example program and it was working fine. It just wasn't very fun yet. I need to work on it some more.

Oh ok. I was assuming it was the same as the one by RevEng here:

which was:

  asm
.unrand
  LDA rand
  ASL
  BCC unrandnoeor
  EOR #$69
unrandnoeor:
  STA rand
  STA temp6
  RETURN
end

 

but the new one by Karl G looks to be a little different in a few ways. First, it's not storing in rand, but rather _RoomRand:

   ;```````````````````````````````````````````````````````````````
   ;  Special UnRand for rooms.
   ;
__UnRand
   asm
   LDA _RoomRand
   ASL
   BCC __UnRand_no_eor
   EOR #$69
__UnRand_no_eor:
   STA _RoomRand
   STA _CurrentScene
end

 

And there's also:

   ;```````````````````````````````````````````````````````````````
   ;  Special Rand for rooms.
   ;
__bBRand
   asm
   lda _RoomRand
   lsr
   bcc __bB_Rand_no_eor
   eor #$B4
__bB_Rand_no_eor
   sta _RoomRand
end

 

And, it seems to be using:

set optimization inlinerand

 

then it uses:

   ;```````````````````````````````````````````````````````````````
   ;  Makes better random numbers.
   ;
   dim rand16 = z

 

And in the rand section of your page: https://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#rand

 

it says:

Quote

The DPC+ kernel has an ARM-based 32-bit LFSR for random numbers, so “dim rand16 = <var>” should not be used when making games with the DPC+ kernel.

 

Then, I see rand used once in the program, here:

   ;```````````````````````````````````````````````````````````````
   ;  Makes _RoomRand a random number.
   ;
   _RoomRand = rand : if !_RoomRand then _RoomRand = 1

 

So, in summary:

  • It's not RevEng's unrand, which I was talking about, so I'm sorry for the confusion.
  • inlinerand is being used.
  • rand16 is being dimmed, even though it's DPC+.
  • rand is only used once in the code.

 

Could you or @Karl G maybe provide a short summary of what the asm is doing and whether and why inlinerand and rand16 are needed?

 

Thanks! That would help in my understanding of this.

Edited by Fort Apocalypse
Link to comment
Share on other sites

6 hours ago, Fort Apocalypse said:
  • It's not RevEng's unrand, which I was talking about, so I'm sorry for the confusion.
  • inlinerand is being used.
  • rand16 is being dimmed, even though it's DPC+.
  • rand is only used once in the code.

 

I think the inlinerand and dimming of rand16 were inherited from my first example, which was not DPC+, so you are right that they don't need to be used for the DPC+ example. Both examples are indeed using RevEng's unrand code, but as separate rand and unrand routines that don't actually use the rand variable to allow for rand-ing outside of the map generation without messing that up. The one use of actual rand in the example is just to populate the seed for those custom functions (making sure the seed isn't zero, which doesn't work). That line can be replaced with something that sets the variable to a static seed number instead in the range of 1 - 255 so that the map layout will be the same everytime.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

34 minutes ago, Karl G said:

I think the inlinerand and dimming of rand16 were inherited from my first example, which was not DPC+, so you are right that they don't need to be used for the DPC+ example. Both examples are indeed using RevEng's unrand code, but as separate rand and unrand routines that don't actually use the rand variable to allow for rand-ing outside of the map generation without messing that up. The one use of actual rand in the example is just to populate the seed for those custom functions (making sure the seed isn't zero, which doesn't work). That line can be replaced with something that sets the variable to a static seed number instead in the range of 1 - 255 so that the map layout will be the same everytime.

Thanks! And I thought that 8x8 example code was DPC+, but it wasn't; I got confused somehow.

Edited by Fort Apocalypse
Link to comment
Share on other sites

  • 3 months later...
  • 11 months later...

I was able to scale the code back some and make a Standard, Multisprite and DPC version. The only thing I haven't figured out yet is to do a sequence in a certain order. Sort of below. I think a data table may work or something else. Either way this opens up some ideas and can continue my other builds.

 

0 1 2 3 4 5 6 7

1 2 3 4 5 6 7 0

2 .....

3......

4 7 2 3 2 1 0 5

5.....

6.....

7.....

20231218 - DPC Openw World.bas.bin 20231218 - Open World Multispritte Kernel.bas.bin 20231218 - Open World Standard Kernel.bas.bin 20231218 - DPC Openw World.bas 20231218 - Open World Multispritte Kernel.bas 20231218 - Open World Standard Kernel.bas

Edited by Lewis2907
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...