I'm making a platformer game called Uni where this small character has to go as high as possible, in which the player constantly has to choose between jumping (W) going left or right (A-D) climbing down (S) or waiting (Just enter). A friend wanted a very difficult game that requires not timing but thinking to progress. Hence there are many rules that players learn throughout the game:
You may jump two characters over where you were initially at.
To go over a block, you must jump higher than it and from below.
To go over a ladder, you must jump at least as high as where it is from below.
When in the air, you can change direction (A-D) or you can stay where you are at.
When falling, you catch up speed.
Because it is a game based on Frames per Input, the number of "you"s you see represents the speed at which you just moved to reach your current position.
If you jump over a ladder exactly 3 characters above you, its as if you jumped over a block 2 characters above you.
If you jump over a ladder less than 3 characters above you, the next time you press enter you will "bounce" one character higher, because of the exess of velocity.
When you enter contact with a checkpoint, it activates it. When you die, you get teleported to the last checkpoint you activated (if any) and that same one dissappears. If there are no more activated checkpoints left, you simply die.
So the game works, and is very difficult but is possible. When I made it though, I wished for the layout to be randomly generated each time the script is runned. Now I realise that with so many rules, I have no idea how to get the layout to not just be randomly generated but also possible. The current game has a static layout.
Here is the script (although kinda sloppy):
#Mechanics:
#Make a list for each printed line. When the player goes higher, shift the list down 1 and add a new layer
import os
import time
debug = False
def get_key():
try:
import sys, tty, termios
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
try:
tty.setraw(fd)
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old)
except:
return input("Press a key and hit Enter: ")[0]
checkpoint1 = "\u235A"
my_list = []
# 18 spaces between sides
# U+2223, U+2336, U+2180, U+2182, U+2188
portal = " "
def updater():
global my_list
global portal
my_list = [
" ",
" ",
" ",
" ",
f" \u2359 \u2359 {portal} ",
#" \u2359 \u210D \u210D\u20AA ",
" \u2359 \u210D \u210D\u20AA\u20AA\u20AA\u20AA\u20AA\u20AA\u20AA\u20AA\u20AA",
" \u210D\u20AA \u2359 \u210D\u20AA ",
f" \u210D ",
" \u210D\u20AA\u20AA\u2359\u2359\u210D ",
" \u210D ",
" \u20AA \u20AA\u210D\u20AA ",
" \u2359\u210D \u2359 ",
" \u20AA \u2359 \u20AA\u20AA\u2359 ",
f" \u210D {checkpoint1} \u2359 ",
" \u20AA\u20AA\u20AA\u20AA\u20AA\u20AA\u20AA\u20AA ",
"_\u2359\u2359\u2359\u2359\u2359\u2359\u2359\u2359\u2359\u2359\u2359\u2359\u2359\u2359\u2359\u2359\u2359\u2359_",
" ",
" ",
" ",
" ",
" ",
" "
]
updater()
# Number of visible lines
window_height = 9
scrollingY = 0
playerX = 1
player = '\u237E'
fellat = 0
dead = False
while scrollingY + window_height < len(my_list):
scrollingY += 1
scrollingY -= 6
def clear():
os.system('cls' if os.name == 'nt' else 'clear')
s = []
middle = 0
playerline = 0
target = "a"
undertarget = "b"
underundertarget = "c"
fellat = 0
key = "uhh"
def display_list():
global target
global undertarget
global underundertarget
global s
global playerX
global middle
global fellat
clear()
global scrollingY
global player
global dead
global playerline
global checkpoint1
global key
global portal
setrightundertarget = False
for i in range(scrollingY, min(scrollingY + window_height, len(my_list))):
if i == min(scrollingY+window_height,len(my_list))-3:
#print the list with the player at the center
playerline = i
s = my_list[i]
middle = len(s) // 2
# Split around the middle
before = s[:middle+playerX]
target = s[middle+playerX]
after = s[(middle+playerX+1):]
undertarget = my_list[i+1][((len(my_list[i+1])//2)+playerX)]
if setrightundertarget == False:
rightundertarget = undertarget
setrightundertarget = True
#Check if player reached checkpoint1 and checkpoint1 is deactivated
if target == "\u235A" and scrollingY == 7 and playerX == -3:
checkpoint1 = "\u06E9"
updater()
#Check if player is inside ladder but not going down(bring back on top),
#else if player is trying to go down a floor(bring back on top)
#else if player is over or in a spike (death),
#else if player is over nothing or a checkpoint (fall),
#else since player is not falling if player is about to bounce (prevent)
#Bouncing occurs after going over a regular block without having fellat at 0
if (target == "\u210D" and key != "s") or (target == "\u20AA" and key == "s"):
scrollingY -= 1
fellat = 0
clear()
display_list()
break
elif undertarget == "\u2359" or target == "\u2359":
player = "\u237D"
dead = True
#Player is dead from spike
elif undertarget == " " or undertarget == "\u235A" or undertarget == "\u06E9":
scrollingY += 1
elif rightundertarget == "\u20AA" and fellat == 2:
#Bouncing occurs after going over a regular block without having fellat at 0
fellat = 0
# Print the original middle character, backspace, then overwrite it with the player.
print(before + target + '\b' + player + after)
else:
print(my_list[i])
if dead == True:
print("\n GAME OVER ")
while dead == False or checkpoint1 == "\u06E9":
clear()
scrollingY -= fellat
display_list()
if debug:
print(f"PlayerX:{playerX} and ScrollingY:{scrollingY}\ntarget:{target}\nundertarget:{undertarget}\nfellat:{fellat}")
key = input(">> ").lower()
if checkpoint1 == "\u06E9" and dead == True:
checkpoint1 = " "
updater()
dead = False
fellat = 0
playerX = -3
scrollingY = 7
clear()
display_list()
player = "\u237E"
if key == 'q':
break
elif key == 'w': # and scrollingY > 0:
fellat = 3
elif key == 's' and scrollingY + window_height < len(my_list):
scrollingY += 1
fellat = 0
elif key == 'd' and playerX < 7 and my_list[playerline-(1 if fellat != 0 else 0)][(middle+playerX)+1] != "\u20AA":
playerX += 1
elif key == 'a' and playerX > (0-10) and my_list[playerline-(1 if fellat != 0 else 0)][(middle+playerX)-1] != "\u20AA":
playerX -= 1
if fellat > 0:
fellat -= 1
if scrollingY == -2 and portal == " ":
# U+2223, U+2336, U+2180, U+2182, U+2188
for i in ["\u2223","\u2336","\u2180","\U00002182"]:
portal = i
updater()
clear()
display_list()
time.sleep(0.15)
if playerX == 6 and scrollingY == -2:
playerlooksbefore = player
player = " "
updater()
clear()
display_list()
time.sleep(0.2)
for i in ["\u2180", "\u2336", "\u2223", " "]:
portal = i
updater()
clear()
display_list()
time.sleep(0.2)
time.sleep(1.8)
clear()
time.sleep(6)
for i in [" ", "\u2223","\u2336","\u2180", "\U00002182", playerlooksbefore]:
clear()
player = i
r,c=os.get_terminal_size()
print("\n"*r + " "*(c//2) + f"{player}")
time.sleep(0.2)
time.sleep(2.8)
clear()
print("[The Creator] - Congradulations.")
time.sleep(2)
blah = input("<<Continue>>")
clear()
print("[The Creator] - You have proven yourself worthy of becoming citizen of unicode.")
time.sleep(2)
blah = input("<<Continue>>")
for i in [player, "\U00002182", "\u2180", "\u2336","\u2223", " "]:
clear()
player = i
r, c = os.get_terminal_size()
print("\n"*r + " "*(c//2) + f"{player}")
time.sleep(0.9)
time.sleep(3)
clear()
time.sleep(4)
print("YOU WON")
time.sleep(0.5)
for i in ["\n","Coded by:","Emmanuel Ghattas","\n",f"Thanks for pl{playerlooksbefore}ying!"]:
print(i)
time.sleep(0.2)
time.sleep(7)
break
If anyone knows how to get a layout that changes each time the player runs the script while keeping it playable, or simply has ideas for the game, please let me know.