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.
Related
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.
I have a 3D elastic collision simulation. I'd like to clear all of the sphere objects from my program from a button press. The documentation indicates that I should do the following:
def clear_balls():
for ball in balls:
ball.visible = False
del ball
This successfully makes the balls invisible in the scene, but they still take up memory and collide with balls that still exist. I want it completely removed. Trying this with a unique ball name this isn't part of a list as some have suggested still results in the same issue.
del ball is not doing what you think because balls still holds a reference to the object. You need to empty the balls list:
def clear_balls():
for ball in balls:
ball.visible = False
balls[:] = []
I am new to Python and I have a program that has 2 classes, one is essentially a rectangle and the other is essentially a circle. I am drawing them using the Canvas in Tkinter in the way below:
def draw(self):
self.canvas.delete("all")
self.rect.draw(self.canvas)
self.ball.draw(self.canvas)
The Ball class has its location variables and diameter variables and the Rect class has its location and dimension variables.
I am wondering how I detect the collision between these two "shapes". I know that one was is to treat the Ball as a square and do basic rectangle collision but I would like to know how to be precise.
I was also wondering if there was anything similar in Python to the way shape collision can be done in Java. In my Java game I use the following code to detect collision between any 2 Shapes:
public boolean collisionCheck(Shape a, Shape b) {
Area aA = new Area(a);
Area aB = new Area(b);
aA.intersect(aB);
return !aA.isEmpty();
}
Is there anything similar to this simple solution in Python?
And if not how would I go about circle-rectangle collision in Python?
Thank you for any help
I managed to figure this out using a method that Tkinter's Canvas object has. Every time something is drawn using Canvas it is given an ID. So as long as you record that ID somewhere you can use the find_overlapping method that the Canvas object has.
Say you have an object, in my case a custom Platform object, that keeps the ID stored in a variable. I did so like this:
def draw_platform(self, canvas): #Located in the Platform Class
self.ID = canvas.create_rectangle(self.x, self.y, self.x+self.w, self.y+self.h)
Now I can use this ID to determine if there are any object overlapping it.
def check_collision(self, plat, other_plat):
result = self.canvas.find_overlapping(plat.x, plat.y, plat.x + plat.w, plat.y + plat.h)
for i in result:
if i == other_plat.ID:
return True
return False
result returns a tuple of the ID's that are located within the rectangle bounds entered into find_overlapping. You can than loop through the tuple to see if any of the ID's match your other shape.
This works great for Rectangle-Rectangle collision and Circle-Rectangle collision.
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
There are a lot of these question already, but I can't figure out what's wrong. compounding the problem the code is spread out over a class. I'm trying to create a scrolling panel. This is class slot which displays some phrase, and acts as a linked list to allow growth (and hopefully compact code)
code:
variables: the_game: instance of module pygame, font: instance of module pygame.font, phrase: string being pushed, self.bitmap: Surface object of slot to be drawn to screen, num: number indicating slot number, because they are supposed to be in sequence.
class slot(object):
def __init__(self,x,y,num,dimx,dimy,the_game,font):
...
self.wordnum = convertnum(num)+". "
self.phrase=""
self.bitmap = the_game.Surface((dimx,dimy))
self.updatesprite(the_game,font)
function updatesprite for clearing and re-blitting whatever phrase the slot is supposed to hold when changed:
def updatesprite(self,the_game,font):
self.bitmap.fill((240,240,240))
phrase = self.wordnum
if(self.has_phrase==True):
phrase+=self.phrase
text = font.render(phrase,1,(0,0,255))
the_game.Surface.blit(text,self.bitmap,[self.x+2, self.y+2])
...
for moving back a phrase or sentence onto the next slot when another one is "pushed" on a previous slot
def mypush(self,num,phrase,the_game,font):
if (num > self.num):
if (self.has_next==False):
self.addmore(num-self.num,the_game,font)
self.next.mypush(num,phrase,the_game,font)
self.updatesprite(the_game,font)
elif (num == self.num):
if (self.has_phrase==True):
self.mypush(self.num+1,self.phrase,the_game,font)
else:
self.has_phrase=True
self.phrase=phrase
self.updatesprite(the_game,font)
function for setting the phrase of a slot:
def setphrase(self,phrase,realx,realy,virty,realdim,mousex,mousey,the_game,font):
...
if (self.has_phrase==True):
self.mypush(self.num+1,self.phrase,the_game,font)
self.has_phrase=True
self.phrase=phrase
self.updatesprite(the_game,font)
and then the method for drawing to the screen:
def mydraw(self,the_game,scrn,realx,realy,virty,realdim):
...
holder = self.bitmap.subsurface(0,self.e_y-virty,self.dim_x,self.dim_y-(self.e_y-virty))
scrn.blit(holder,[self.x,0])
if(self.has_next==True):
self.next.mydraw(the_game,scrn,realx,realy,virty,realdim)
code that was abbreviated out is for determining if the user clicked on a slot, determining screen coordinates from scrolling coordinates, etc.
The reason for it being written like this is because: a) I expect there to be quite a lot of slots potentially for one panel. I figured drawing to a large bitmap and grabbing what I need wouldn't be smart, or scalable. b) individual slots may be deleted
I can make examples work, but not this work. I can see the actual bitmap: self.bitmap, being drawn to the screen but no string. IDK whats going on
updated updatesprite method:
def updatesprite(self,the_game,font):
self.bitmap.fill((240,240,240))
phrase = self.wordnum
if(self.has_phrase==True):
phrase+=self.phrase
text = font.render(phrase,1,(0,0,255))
**self.bitmap.blit(text,[1, 1])** #compare to original
heh