Top-Down map scrolling with python ncurses - python

I'm new to curses but I have some experience. I'm trying to make a top-down style game in python with ncurses, but I don't even know where to start. I'm wanting the character to be centered on the screen and move around the map, but the environment to not all be visible on the screen at once. Is this possible? I would like to know before I get started.

For the background, if it's text-based, you could draw the map using 2-layer list or tuple that gets printed using loops and slices with window.addstr(x,y,string)
example, with stdscr as the name of the window:
map_tiles = [['a','1','+'],['b','2','-'],['c','3','=']]
inx = 0
iny = 0
range = 1
def scroll(bx,by):
stdscr.clear()
for y, x_line in enumerate(map_tiles[by : by+range]):
for x, tile in enumerate(x_line[bx : bx+range]):
stdscr.addstr(y, x, f'{tile}')
then, by calling scroll(inx.iny) the tiles within range of the slices map_tiles[by : by+range] and x_line[bx : bx+range] will get printed in the terminal.
You can then bind keys to add increments to inx and iny to change the visible tiles.

Related

Control over which turtle renders on top of another

I'm currently trying to make 3d graphics using Turtle.
I have a list of objects that have inherited the Turtle class and each one has an attribute frontFactor - this value is the distance of the turtle to the camera.
How can I make the turtles closer to the camera render on top of the other turtles behind it?
My current code trying to do this:
finished = []
highestIndex = 0
print("FRAME")
for object in objects:
for i in range(len(object.particles)):
curHighest = 0
for j in range(len(object.particles)):
if object.particles[j].frontFactor > curHighest and (not (j in finished)):
curHighest = object.particles[j].frontFactor
highestIndex = j
object.particles[highestIndex].move(0,0,0)
print(object.particles[highestIndex].frontFactor)
finished.append(highestIndex)
where objects has an attribute of particles which is a list,
and every item in this list has a value frontFactor that determines the distance to the virtual camera.
This function goes through each particle on the screen (currently i only have one object), starting from the particles farthest away from the camera and ending at the particles nearest the camera.
This is what I want to happen,
but this is what it looks like instead. (darker particles are further away)
I've heard of a rule which states "last to move is on top" although I don't know how to implement that in this situation.

How to check if turtle is on stamp position

I am new to Python and trying to build a simple game. In the game is just one ant and this ant follows simple rules: if ant is on white field, he paints the tile black (or other color), turns right, moves forward. If ant is on colored tile, remove color, turn left, move forward.
Currently I am trying to do this with turtle and stamps. Stamp ID and coordinates are stored in a dict, a loop is checking if ant position is in dict keys and there is the problem: when the ant moves to the same position, where the first stamp is, this check return False and the ant never escape the loop.
from turtle import Turtle, Screen
screen = Screen()
screen.setup(height=900, width=1000)
screen.title("The Ant")
ant = Turtle()
ant.color("brown")
ant.pencolor("black")
ant.penup()
kleks_liste = {}
game_running = True
ant.shape("square")
ant.setpos(5, 5)
kleks_liste[ant.pos()] = ant.stamp()
ant.shape("classic")
ant.forward(20)
while game_running:
pos_key = ant.pos()
if pos_key in kleks_liste.keys():
ant.clearstamp(kleks_liste[pos_key])
kleks_liste.pop(pos_key)
ant.left(90.00)
ant.forward(20.00)
else:
ant.right(90.00)
ant.shape("square")
kleks_liste[pos_key] = ant.stamp()
ant.shape("classic")
ant.forward(20.00)
screen.exitonclick()
What am I doing wrong? If I comment out ant.forward in the else section, the check works and returns True. Can someone explain the behavior?
The Vec2D returned by pos() contains floats which need to be compared with an epsilon. One workaround is to cast these values to integers, either with int or round. This shouldn't lose accuracy since you're working on a grid.
Instead of pos_key = ant.pos(), try pos_key = tuple(map(int, ant.pos())). Don't forget to change the first stamp key outside the loop too.
As an aside, you can use if pos_key in kleks_liste: without .keys().

The bottom rectangle gets deleted instead of the top-most

I'm showing 25 rectangles (objects of My_rect) randomly on the screen.
rects = []
for i in range(25):
rects.insert(0, My_rect(canvas))
My goal is to remove them as I click on them.
This is how I'm handling clicks:
if ev.type == pygame.MOUSEBUTTONUP and ev.button == 1:
click_x, click_y = ev.pos
for cur_rect in rects:
if cur_rect.contains_point(click_x, click_y):
rects.remove(cur_rect)
break
The contains_point function is defined like this:
def contains_point(self, point_x, point_y):
rect = Rect(self.x, self.y, self.width, self.width)
return rect.collidepoint(point_x, point_y)
When I click on a separately-positioned rectangle, it gets deleted, as it should be. However, when I click on a rectangle that overlaps another one beneath it, the bottom-most rectangle disappears, which is contrary to my goal.
To me, the strangest thing is that I specifically added rectangles to rects using insert(0, ...) and not append() in order to prevent that effect.
What haven't I taken into consideration?
As you explain in your comment, you draw the rectangles in the order they appear in the list, so the first ones are drawn first, and end up at the bottom.
Then, you also test for the click by iterating on the list in the same order, so you test the rectangles at the bottom first.
The way you inserted the rectangles in the list is irrelevant. Just do it using append - furthermore, using insert(0) is very inefficient for large lists, as all items have to be moved each time you insert one.
Just iterate the list in reverse order when testing for the click:
for cur_rect in reversed(rects):
if cur_rect.contains_point(click_x, click_y):
rects.remove(cur_rect)
break

How can a turtle be moved up then down in a for loop?

So I'm learning python in a virtual programming class and I have an assignment where I have to create a picture using Turtle Graphics. I'm using things like for loops and programmer-defined functions in the program but I'm having a problem with something I want to do in my picture. I'm drawing clouds in the sky and I'm trying to get the clouds to be drawn at different positions. I'm increasing the x coordinate by increments of 40 but I'm trying to get the cloud to be placed higher and lower as it goes across. It's at the end of this list of code:
import turtle
def backFill(b, c, x, y, l, h):
b.penup()
b.setpos(x, y)
b.color(c)
b.pendown()
b.begin_fill()
for side in range(2):
b.forward(l)
b.left(90)
b.forward(h)
b.left(90)
b.end_fill()
def drawCloud(c, x, y):
c.penup()
c.setpos(x, y)
c.pendown()
c.color("grey")
c.begin_fill()
for side in range(5):
c.circle(10)
c.left(80)
c.end_fill()
def main():
print("Cars")
joe = turtle.Turtle()
joe.speed(0)
backFill(joe,"green",-200,-100,400,25)
backFill(joe,"black",-200,-75,400,75)
backFill(joe,"green",-200,0,400,25)
backFill(joe,"sky blue",-200,25,400,110)
x=-192.5
for side in range(10):
backFill(joe,"yellow",x,-40,25,5)
x=x+40
x=-180
y=100
for side in range(15):
drawCloud(joe,x,y)
x=x+40
y=y-10
main()
Currently the clouds slowly descend as each one is drawn but what I'm trying to do is make clouds at different heights like one cloud is at 100 the next 90 then back to 100, etc. I tried things like y=y-10, y+10 to see if the first time it repeated it would go down 10 then the next time it would go up 10.
https://gyazo.com/3ad5268231b3217b81636cc070573b75
tl;dr/simpler explanation: I'm trying to move a looped picture up and down so it's not simply in a straight line. How would I move it down one time then up another time within a for loop?
You could check whether side is even or odd to decide whether to increment or decrement your cloud location. Like so:
for side in range(15):
drawCloud(joe,x,y)
x=x+40
if(side%2==0):
y=y-10
else:
y=y+10
for side in range(5):
drawCloud(joe,x,y)
x=x+40
y=y-10
drawCloud(joe,x,y)
x=x+40
y=y+10

Why doesn't this circle disappear upon collision?

These seem to be the relevant portions of a slightly larger program. These are essentially the collision detection functions. bubbles is the original list of circles. I want the circle collided with to disappear on impact. I'm fairly sure my problem lies down there in "if collide ==" conditional.
def getDistance(point1,point2):
a= point1.getX()
b= point2.getX()
c= point1.getY()
d= point2.getY()
distance= math.sqrt((b-a)**2 + ((d-c)**2))
return distance
def balloonBubbleCollide(balloon,bubble):
point1 = balloon.getCenter()
point2= bubble.getCenter()
distance= getDistance(point1, point2)
if distance <= 30:
return True
def check(balloon, bubbles, window):
for bubble in bubbles:
collide = balloonBubbleCollide(balloon, bubble)
if collide == True:
bubbles.remove(bubble)
Assume main is running them in proper order. Just don't want to bog the post down with code.
You should not modify a list using remove while iterating over it.
To filter out the colliding bubbles use instead something like:
def check(balloon, bubbles, window):
bubbles[:] = [bubble for bubble in bubbles
if not baloonBubbleCollide(balloon, bubble)]
the code shown will create a first new list of bubble objects to keep (using a list comprehension) and then replace the current content of the bubbles list with it at once.

Categories

Resources