How do stop my character from going through the ground - python-3.x

So i am trying to make a fighting game and i have fixed so i can jump and so on by making my y speed += 1 every frame to make it act like gravity and when i press the jump key the y speed -=14. But when i use higher than -=14 for example -=20 the character clips through the ground.
i am using this kind off collison detection
collisions = pygame.sprite.spritecollide(self, object_list, False)
for col in collisions:
if type(col) == Solid:
if (self.rect.top < col.rect.bottom and self.rect.bottom >
col.rect.bottom):
self.rect.top = col.rect.bottom
if (self.rect.bottom > col.rect.top and self.rect.y < col.rect.top):
self.rect.bottom = col.rect.top
self.yspeed = 0
self.jump = False

I guess that your fighter is falling so fast that it passes the platform in one update of the loop...
There are a few ways to solve this issue, the most simple one is to update its position a few times and check for collisions each time...
#example ...
for i in range(4): # split the change into smaller steps ...
self.rect.y += self.velocity_y /4.0
collisions = pygame.sprite.spritecollide(self, object_list, False)
... #all your collisions checks here ...

Related

Having problems with thrust and acceleration in python turtle module

I am trying to code a boat that keeps its momentum after letting go of "w". However, i also want it to slow down gradually after letting go of "w". I have gotten a decent boat working but sometimes when I press "w" after going a certain direction, the boat goes flying. Is there any way to add a top speed or make it slow down?
self.thrust = 0.0
self.acceleration = 0.0001
self.dx += math.cos(math.radians(self.heading)) * self.thrust
self.dy += math.sin(math.radians(self.heading)) * self.thrust
def accelerate(self):
self.thrust += self.acceleration
def decelerate(self):
self.thrust = 0
If you want it to slow down gradually when you aren't pressing "w", then you may want it to go at the same speed, or faster. This code will work for it to go at the same speed. This should work in any Python IDE.
Suppose your boat is a turtle.
import turtle
Win = turtle.screen()
Boat = turtle.Turtle()
If you want it to also look like a Boat, you can do:
screen.adshape(Saved Document Direction)
Boat.shape(Saved Document Direction)
Otherwise, you can create your own shapes.
Now, we want it to go at a constant speed, while you press "w":
So:
def Constant_Speed():
Boat.speed(Speed You Want it to Go)
Win.listen()
Win.onkeypress(Constant_Speed, "w")
Otherwise, it should slow down.
Initial_Speed = Initial Speed
Boat.speed(Initial_Speed)
Initial_Speed *= Fraction of what you want it to be in/decimal
So, this should work if you replace with your variables:
import turtle
Win = turtle.screen()
Boat = turtle.Turtle()
screen.adshape(Saved Document Direction)
Boat.shape(Saved Document Direction)
def Constant_Speed():
Boat.speed(Speed You Want it to Go)
Win.listen()
Win.onkeypress(Constant_Speed, "w")
Initial_Speed = Initial Speed
Boat.speed(Initial_Speed)
Initial_Speed *= Fraction of what you want it to be in/decimal and must be less than 1
But what if you want it to go faster, not at a constant speed?
Then go to the def Constant_Speed() part.
You can rename it: def Go_Faster()
Now, the code:
Speed = Initial_Speed
Boat.speed(Speed)
Speed *= Times you want to increase speed by
Also:
Change the last line to:
Initial_Speed2 = Initial Speed * Fraction of what you want it to be in/decimal and must be less than 1
With your variables.
Now, this should work:
import turtle
Win = turtle.screen()
Boat = turtle.Turtle()
screen.adshape(Saved Document Direction)
Boat.shape(Saved Document Direction)
def Go_Faster():
Speed = Initial_Speed()
Boat.speed(Speed)
Speed *= Times you want to increase by
Win.listen()
Win.onkeypress(Constant_Speed, "w")
Initial_Speed = Initial Speed
Boat.speed(Initial_Speed)
Initial_Speed2 = Initial Speed * Fraction of what you want it to be in/decimal and must be less than 1

Saving a large turtle graphics image from the entire canvas

I've been looking around for a few hours, and I couldn't find any solutions for this specific problem. I did see one person who asked the same question, but they didn't provide code, and so didn't get an answer. My problem is this:
I have a program that sends the turtle left and right randomly for a set number of turns. The turning part works, but when I try to save the canvas, it only saves the visible part, which often cuts things off. I have tried increasing the size of the setup canvas, as well as the screen capture, but the saved file always ends up in the top left corner, and so gets cut off. I'm attaching my entire program (it's short, don't worry), because I'm not sure exactly what aspect needs to change.
Any help would be greatly appreciated!
import turtle
import random
'''
Takes a variable, number, of how many random turns the turtle should make and a variable filenumber,
which is used to save multiple different iterations of the program per program execution
'''
def left_or_right(number,filenumber):
# Counters to make sure the turtle doesn't turn too many times
count = 0
subright = 0
subleft = 0
#sets up screen
win_width, win_height, bg_color = 10000, 10000,'white'
turtle.setup()
turtle.screensize(win_width, win_height,bg_color)
# Clears the screen, sets the turtle in the middle of the screen, drops the pen and hides the
# Turtle. If you want to see the turtles do the drawing, turn turtle.tracer to True, and
# uncomment out turtle.speed('fastest')
turtle.clear()
turtle.home()
turtle.hideturtle()
turtle.pendown()
turtle.speed('fastest')
turtle.tracer(False)
# A for loop for the turtle's turns
for i in range(number):
# Calls decider to you can get a random direction every time
decider = random.randint(0, 1)
# in order to minimize the turtle just going around in circles,
# if the turtle has made more that 3 of the same turn, turn it the other way
# the next to if statements deal with the turtle turning right too many times
if decider == 1 and subright <= 3:
turtle.right(90)
turtle.forward(20)
count += 1
subright += 1
elif decider == 1 and subright > 3:
turtle.left(90)
turtle.forward(20)
count += 1
subright = 0
# The next two if statements make sure the turtle doesn't turn right too many times
elif decider == 0 and subleft <= 3:
turtle.left(90)
turtle.forward(20)
count += 1
subleft += 1
elif decider == 0 and subleft > 3:
turtle.right(90)
turtle.forward(20)
count += 1
subleft = 0
# if the number of turns is equal to what the user inputed, stop making the turns
# and update the screen
if count == number:
turtle.penup()
turtle.update()
# Take a screen capture of the screen and saves it to where the python file is
ts = turtle.getscreen()
ts.getcanvas().postscript(file=filenumber,height=10000, width=10000)
# turtle.done() is here as a debugging tool. If you set the number of files you're
# generating to one, you can keep the turtle window open to check that the file correctly
# copied the turtle screen
#turtle.done()
''' Takes a variable, filenumber, which is the number of generated files you want'''
def filegen(filenumber):
for i in range(filenumber):
# Calls the left or right function as many times as you told it to
# Note: this is where the left or right function get's its turn number parameters
left_or_right(10000,i)
def main():
# calls filegen as many times as you want it to
filegen(4)
if __name__ == '__main__':
main()

How can I fix the wrong deceleration when moving to left?

I just started learning game development in pygame and I want the player object to have a deceleration when the player stops pressing the key.
This is what I have at the moment:
def update(self):
self.accel_x = 0
keys = pg.key.get_pressed()
if keys[pg.K_LEFT]:
self.accel_x = -0.2
if keys[pg.K_RIGHT]:
self.accel_x = 0.2
if abs(self.vx) >= max_speed:
self.vx = self.vx/abs(self.vx) * max_speed
if self.accel_x == 0:
self.vx *= 0.91
self.vx += self.accel_x
self.vy += self.accel_y
self.rect.x += self.vx
self.rect.y += self.vy
It's works fine while moving to right but the object doesn't stop on time while going to left. Instead it decelerates to a point and then keeps going with a really slow speed for some time, then stops.
First, let see the math behind the algorithm.
When the button is pressed, the speed and position change based on the acceleration a, at t (number of times the function run), initial values being v0 and x0
v = v0 + a * t
x = x0 + Σ(i=1 to t) i * a
or
x = x0 + (t2+t) * a/2
And when the button is released (accel is 0) the speed v decreases geometrically
v = v0 * 0.91t
after 10 calls, we have ~0.39 v, after 100 calls ~10-5 v. Meaning that, visually, the position x decelerates and stops, v being too small to make a difference after some time.
The math is consistent with what is seen in games.
The question is why that algorithm doesn't work left side.
While it should work the same, left and right.
The difference is, left side,
speed v more likely to be negative after LEFT was pressed
position x might become negative at some point (and has to be checked)
Since the code provided (probably) does not cover the part to be changed, some recommendations:
You could force the speed to 0 if abs(v) is less than, say, 10-5 or another small values from which the position doesn't change visually (less than a pixel).
Ensure x values are checked at the limit, especially for negative values.
Debug: display/log v and x values especially after LEFT is released. This way when the whole program is running you'll identify more easily when does the problem come from.
If that doesn't address your problem, you could edit your question and add more relevant code.

How to improve the performance of Cellular Automata

I've made a simple terrain generator, but it takes an excessive amount of time to generate anything bigger than 50x50. Is there anything I can do to optimise the code so that I can generate larger things? I know that things such as pygame or numpy might be better for doing this, but at my school they wont install those, so this is what I have to work with.
Here's the relevant code:
def InitMap(self):
aliveCells = []
for x in range(self.width):
for y in range(self.height):
if random.random() < self.aliveChance:
aliveCells.append(self.FindInGrid(x,y))
return aliveCells
def GenerateMap(self):
aliveCells = self.InitMap()
shallowCells=[]
self.count = 1
for i in range(self.steps):
aliveCells = self.DoGenStep(aliveCells)
for i in aliveCells:
self.canvas.itemconfig(i,fill="green")
for i in aliveCells:
for j in self.FindNeighbours(i):
if j not in aliveCells: self.canvas.itemconfig(i,fill="#0000FF")
def DoGenStep(self,oldAliveCells):
newAliveCells = []
for allCells in self.pos:
for cell in allCells:
self.root.title(str(round((self.count/(self.height*self.width)*100)/self.steps))+"%")
self.count += 1
aliveNeighbours = 0
for i in self.FindNeighbours(cell):
if i in oldAliveCells: aliveNeighbours += 1
if cell in oldAliveCells:
if aliveNeighbours < self.deathLimit:
pass
else:
newAliveCells.append(cell)
else:
if aliveNeighbours > self.birthLimit:
newAliveCells.append(cell)
return newAliveCells
def FindNeighbours(self,cell):
cellCoords = self.GetCoords(cell)
neighbours = []
for xMod in [-1,0,1]:
x = xMod+cellCoords[0]
for yMod in [-1,0,1]:
y = yMod+cellCoords[1]
if x < 0 or x >= self.width: pass
elif y < 0 or y >= self.height: pass
elif xMod == 0 and yMod == 0: pass
else: neighbours.append(self.FindInGrid(x,y))
return neighbours
NB: You didn't add the method "FindInGrid", so I'm making some assumptions. Please correct me if I'm wrong.
One thing which would help immensely for larger maps, and also when at high densities, is not to store just the alive cells, but the entire grid. By storing the alive cells, you make the behavior of your program in the order O( (x*y)^2), since you have to iterate over all alive cells for each alive cell. If you would store the entire grid, this would not be necessary, and the calculation can be performed with a time complexity linear to the surface of your grid, rather than a quadratic one.
Additional point:
self.root.title(str(round((self.count/(self.height*self.width)*100)/self.steps))+"%")
That's a string operation, which makes it relatively expensive. Are you sure you need to do this after each and every update of a single cell?

Collision detection in Python

I'm currently working on a maze game which is being written in iPython notbook. I do not have access to pygame and is therefore doing colission detection from scratch.
The code i've got so far is able to move the player around and there's a grid already there for how big the playfield is going to be.
from turtle import *
def line(x1, y1, x2, y2):
pu()
goto(x1,y1)
pd()
goto(x2,y2)
pu()
setup(600,600)
setworldcoordinates(-1,-1,11,11)
class Network:
tracer(30)
ht()
for n in range(0,11):
line(0,n,10,n)
line(n,0,n,10)
tracer(1)
head= heading()
st()
class Figur:
register_shape("figur.gif")
shape("figur.gif")
head = heading()
pu()
setpos(9.5,9.5)
def turtle_up():
if head != 90:
seth(90)
fd(1)
def turtle_down():
if head != 270:
seth(270)
fd(1)
def turtle_left():
if head != 180:
seth(180)
fd(1)
def turtle_right():
if head != 360:
seth(0)
fd(1)
onkey(turtle_up, "Up")
onkey(turtle_down, "Down")
onkey(turtle_left, "Left")
onkey(turtle_right, "Right")
listen()
class Walls:
def tortle():
tracer(30)
t1 = Turtle()
t1.color("green")
t1.left(180)
t1.fd(1)
t1.right(90)
t1.fd(11)
for i in range(1,4):
t1.right(90)
t1.fd(12)
for i in range(1,3):
t1.right(90)
t1.fd(1)
t1.left(90)
for i in range(1,5):
t1.fd(10)
t1.right(90)
Walls.tortle()
tracer(1)
update()
done()
Currently the walls are no near being done. I've just started on them and tried to create a wall around the compete playfield resulting in the hole area being covered in green. The picture of the turtle is one i've created myself but I think it should work without it and just take the regular turtle instead.
SO my main question is: How do I create colission detection for my turtle so it can't go through walls ?
I would think to make a set of Vec2Ds of already visited points, then compare to that every time you move. Here's a simple forward and backwards function:
def no_collision_forward(amount, walls):
movement = 1 if abs(amount) == amount else -1 # If amount is negative, moving down
for i in range(abs(amount)):
cur_pos = pos()
nex_pos = Vec2D(cur_pos[0], cur_pos[1] + movement)
if nex_pos in walls:
return # Can return whatever
else:
forward(movement)
def no_collision_backward(amount, walls):
return no_collision_forward(-amount, walls)
visited_locations should be a set of Vec2Ds or tuples.
This is probably not the most efficient solution, but it works!

Resources