Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How could I fix this error?
#1
Hello everyone, I'm new at python, and as I wanted to learn some basic python, I decided to create a project using python turtle. I spent some hours at this until I found and error which I don't know how to fix nor what piece of code causes it.

Here's my code:

#To-Do
#1. Stop levels from completing randomly without the player doing anything

import turtle, winsound, random, time, os

level = 1
dc = 1000, 1000

#Game window
wn = turtle.Screen()
wn.setup(800, 600)
wn.bgpic('sea.gif')
wn.title("A fish game")
wn.tracer(0)
wn.cv._rootwindow.resizable(False, False)

#Shapes
turtle.register_shape('fish-up.gif')
turtle.register_shape('fish-down.gif')
turtle.register_shape('fish-left.gif')
turtle.register_shape('fish-right.gif')
turtle.register_shape('bullet.gif')
turtle.register_shape('crab.gif')
turtle.register_shape('seahorse.gif')
turtle.register_shape('pufferfish.gif')

#Fish
fish = turtle.Turtle()
fish.shape('fish-right.gif')
fish.penup()
fish.goto(0, 0)
fish.speed(0)
fish.lifes = 3

#Bullet
bullet = turtle.Turtle()
bullet.shape("bullet.gif")
bullet.shapesize(stretch_len=5, stretch_wid=5)
bullet.speed(0)
bullet.penup()
bullet.goto(-400, -40000)
bullet.hideturtle()
bullet.dx = 0
bullet.dy = 0

#Pen
pen = turtle.Turtle()
pen.penup()
pen.goto(-300, 200)
pen.color('black')
pen.hideturtle()

#Enemy 1 (crab)
crabx = random.randint(-350, 350)
craby = random.randint(-250, 250)
crab = turtle.Turtle()
crab.shape("crab.gif")
crab.penup()
crab.goto(crabx, craby)
crab.speed(0)
crab.dx = 0.045
crab.dy = -0.045

#Enemy 2 (seahorse)
seahorsex = random.randint(-350, 350)
seahorsey = random.randint(-250, 250)
seahorse = turtle.Turtle()
seahorse.shape('seahorse.gif')
seahorse.hideturtle()
seahorse.penup()
seahorse.goto(400, 400)
seahorse.speed(0)
seahorse.dx = 0.07
seahorse.dy = 0.07

#Enemy 3 (pufferfish)
pufferfishx = random.randint(-350, 350)
pufferfishy = random.randint(-250, 250)
pufferfish = turtle.Turtle()
pufferfish.shape("pufferfish.gif")
pufferfish.hideturtle()
pufferfish.penup()
pufferfish.goto(pufferfishx, pufferfishy)
pufferfish.speed(0)
pufferfish.dx = -0.02
pufferfish.dy = -0.02

#Movement
def move_up():
    fish.shape('fish-up.gif')
    y = fish.ycor()
    y += 10
    fish.sety(y)
    bullet.dx = 0
    bullet.dy = 0.08

def move_down():
    fish.shape('fish-down.gif')
    y = fish.ycor()
    y -= 10
    fish.sety(y)
    bullet.dx = 0
    bullet.dy = -0.08

def move_left():
    fish.shape('fish-left.gif')
    x = fish.xcor()
    x -= 10
    fish.setx(x)
    bullet.dx = -0.08
    bullet.dy = 0

def move_right():
    fish.shape('fish-right.gif')
    x = fish.xcor()
    x += 10
    fish.setx(x)
    bullet.dx = 0.08
    bullet.dy = 0

def shoot_bullet(x, y):
    bullet.showturtle()
    bullet.goto(fish.xcor(), fish.ycor())
    winsound.PlaySound("shoot.wav", winsound.SND_ASYNC)

def stop_bullet(x, y):
    bullet.hideturtle()
    bullet.goto(0, 0)

#Keyboard binding
wn.listen()
wn.onkeypress(move_up, "w")
wn.onkeypress(move_down, "s")
wn.onkeypress(move_left, "a")
wn.onkeypress(move_right, "d")
wn.onkeypress(wn.bye, "r")
wn.onscreenclick(shoot_bullet, 1)
wn.onscreenclick(stop_bullet, 3)

#Levels
if level == 2:
    seahorse.showturtle()

#Main game loop
while True:
    wn.update()

    #The Bullet movement
    bullet.setx(bullet.xcor() + bullet.dx)
    bullet.sety(bullet.ycor() + bullet.dy)

    #Enemy 1 movement
    crab.setx(crab.xcor() + crab.dx)
    crab.sety(crab.ycor() + crab.dy)

    if crab.xcor() > 385:
        crab.setx(385)
        crab.dx *= -1

    if crab.xcor() < -385:
        crab.setx(-385)
        crab.dx *= -1

    if crab.ycor() > 285:
        crab.sety(285)
        crab.dy *= -1

    if crab.ycor() < -285:
        crab.sety(-285)
        crab.dy *= -1

    #Enemy 2 movement
    seahorse.setx(seahorse.xcor() + seahorse.dx)
    seahorse.sety(seahorse.ycor() + seahorse.dy)

    if seahorse.xcor() > 385:
        seahorse.setx(385)
        seahorse.dx *= -1

    if seahorse.xcor() < -385:
        seahorse.setx(-385)
        seahorse.dx *= -1

    if seahorse.ycor() > 285:
        seahorse.sety(285)
        seahorse.dy *= -1

    if seahorse.ycor() < -285:
        seahorse.sety(-285)
        seahorse.dy *= -1

    #Enemy 3 movement
    pufferfish.setx(pufferfish.xcor() + pufferfish.dx)
    pufferfish.sety(pufferfish.ycor() + pufferfish.dy)

    if pufferfish.xcor() > 385:
        pufferfish.setx(385)
        pufferfish.dx *= -1

    if pufferfish.xcor() < -385:
        pufferfish.setx(-385)
        pufferfish.dx *= -1

    if pufferfish.ycor() > 285:
       pufferfish.sety(285)
       pufferfish.dy *= -1

    if pufferfish.ycor() < -285:
       pufferfish.sety(-285)
       pufferfish.dy *= -1

    #Window Borders
    if fish.ycor() > 280:
        fish.sety(280)

    if fish.ycor() < -275:
        fish.sety(-275)

    if fish.xcor() > 375:
        fish.setx(375)

    if fish.xcor() < -380:
        fish.setx(-380)

    #Collisions
    if fish.distance(crab) < 20:
        fish.lifes -= 1
        wn.title('You have ' + lifes + ' lifes left')
        fish.goto(0, 0)
        crabx = random.randint(-350, 350)
        craby = random.randint(-250, 250)
        crab.goto(crabx, craby)
        bullet.hideturtle()

    if fish.distance(seahorse) < 20:
        fish.lifes -= 1
        fish.goto(0, 0)
        seahorsex = random.randint(-350, 350)
        seahorsey = random.randint(-250, 250)
        seahorse.goto(seahorsex, seahorsey)
        bullet.hideturtle()

    if fish.distance(pufferfish) < 60:
        fish.lifes -= 1
        fish.goto(0, 0)
        pufferfishx = random.randint(-350, 350)
        pufferfishy = random.randint(-250, 250)
        pufferfish.goto(pufferfishx, pufferfishy)
        bullet.hideturtle()

    if bullet.distance(crab) < 20:
        fish.lives = 3
        fish.goto(0, 0)
        crab.goto(1000, 1000)
        crab.hideturtle()
        bullet.hideturtle()
        pen.write('You passed level 1!', align='left', font=('Arial', 12, 'normal'))
        i = input("Press any key to continue\n")
        level = 2
        fish.goto(0, 0)
        seahorse.showturtle()
        seahorse.goto(seahorsex, seahorsey)
        pen.clear()
    elif crab.xcor() == dc:
        seahorse.goto(1000, 1000)
        pufferfish.goto(1000, 1000)

    if bullet.distance(seahorse) < 20:
        fish.lives = 3
        fish.goto(0, 0)
        seahorse.goto(1000, 1000)
        seahorse.hideturtle()
        bullet.hideturtle()
        pen.write('You passed level 2!', align='left', font=('Arial', 12, 'normal'))
        i = input("Press any key to continue\n")
        level = 3
        fish.goto(0, 0)
        pufferfish.showturtle()
        pufferfish.goto(pufferfishx, pufferfishy)
        pen.clear()
    elif seahorse.xcor() == dc:
        pufferfish.goto(506546546540, 500)
        crab.goto(500, -503289438274838287432)

    if bullet.distance(pufferfish) < 30:
        fish.lives = 3
        fish.goto(0, 0)
        pufferfish.goto(1000, 1000)
        pufferfish.hideturtle()
        bullet.hideturtle()
        pen.write('You passed level 3!\nCongratulations!', align='left', font=('Arial', 12, 'normal'))
        i = input("Press any key to continue\n")
        level = 4
        fish.goto(0, 0)
        pufferfish.hideturtle()
        pufferfish.goto(4632043626732, 5)
        pen.clear()

    if fish.lifes == 0:
        fish.hideturtle()
        bullet.hideturtle()
        crab.hideturtle()
        pen.write('Game over! Press\n R to exit', align='left', font=('Arial', 12, 'normal'))
The error is that for some reason it says that I complete levels randomly without doing anything. For example, when I start the game and try to complete the first level, it says "You completed level 2", when I didn't even finish the first one. I tried changing literally everything, but I don't know what else to do. I hope I've been clear enough, any help is appreciated!
Reply
#2
If you shoot a crab you passed level 1. If you shoot a seahorse you passed level 2. If you shoot a pufferfish you passed level 3. To shoot something the bullet just has to be close to the thing you are shooting at.

This makes sense if only one enemy is in play at a time, but with your logic all enemies are in play all the time, even if they aren't visible. All you check is if the bullet is close to the enemy, not if the enemy is visible or not.

You thought you took invisible enemies out of play by moving them outside the screen, but this code forces the seahorse to be inside the screen, even if the seahorse is not visible.
    if seahorse.xcor() > 385:
        seahorse.setx(385)
        seahorse.dx *= -1
 
    if seahorse.xcor() < -385:
        seahorse.setx(-385)
        seahorse.dx *= -1
 
    if seahorse.ycor() > 285:
        seahorse.sety(285)
        seahorse.dy *= -1
 
    if seahorse.ycor() < -285:
        seahorse.sety(-285)
        seahorse.dy *= -1
Reply
#3
All of the statements under the if for the characters are the same -->  if seahorse.ycor() < -285: etc. Create one function and pass the object to it, seahorse, pufferfish, etc.
Reply
#4
A better solution is to have only one enemy. You start with enemy = crab. When you kill the crab enemy set enemy = seahorse. When you kill the seahorse enemy set enemy = pufferfish. That way the program only cares about crabs, seahorses or pufferfish when you advance to the next level. At all other times you work with fish, bullet and enemy.
Reply
#5
I decided to take a shot at wring this game. I changed it a little. The original had steerable bullets, which was pretty cool. My version has a gun that shoots multiple bullets, but you have to reload.

Main reason I am posting is that this game shows how you can have the game logic be fairly generic. I don't have special code for each of my boss monsters. All monsters use the same code. When you level up, the only things that change are the shape, size and speed of the monster, and these change via parameter values, not code.
import turtle, random, math
 
screen = turtle.Screen()
screen.setup(800, 600)
screen.tracer(0)

class Sprite(turtle.Turtle):
    """A customized Turtle that can move around the field
    mostly on its own, bouncing off walls.
    """
    def __init__(self, shape, size=1, rate=(1, 0), pos=(0, 0)):
        super().__init__()
        self.penup()
        self.shape(shape)
        self.turtlesize(size)
        self.speed(0)
        self.setrate(*rate)
        self.goto(*pos)
 
    def setrate(self, dx, dy):
        """Set rate used when moving."""
        self.dx, self.dy = dx, dy
        self.setheading(math.degrees(math.atan2(dy, dx)))
     
    def move(self):
        """Move turtle at rate.  Return True if turtle bounced off a wall"""
        x = self.xcor() + self.dx
        y = self.ycor() + self.dy
        w, h = turtle.screensize()
        bounced = False
        if abs(x) > w:
            x = max(-w, min(w, x))
            self.setrate(-self.dx, self.dy)
            bounced = True
        if abs(y) > h:
            y = max(-h, min(h, y))
            self.setrate(self.dx, -self.dy)
            bounced = True
        self.goto(x, y)
        return bounced
 
    def step(self, dx, dy):
        """Move relateve to current location.  Clip location to be inside walls."""
        self.setheading(math.degrees(math.atan2(dy, dx)))
        w, h = turtle.screensize()
        x = max(-w, min(w, self.xcor() + dx))
        y = max(-h, min(h, self.ycor() + dy))
        self.goto(x, y)
     
    def collide(self, other):
        """Return True if self collides with other sprite"""
        return self.distance(other) <= (self.turtlesize()[0] + other.turtlesize()[0]) * 10
 
class Gun():
    """A thing that shoots bullets.  I have a limited number of bullets that can be fired at a time"""
    def __init__(self, shooter, count=6):
        self.shooter = shooter
        self.magazine = []
        self.fired = []
        for _ in range(count):
            self.reload(Sprite('circle', 0.5))
 
    def reload(self, bullet):
        """Put bullet in the magazine"""
        self.magazine.append(bullet)
        bullet.hideturtle()
 
    def reload_all(self):
        """Put all bullets in the magazine"""
        while self.fired:
            self.reload(self.fired.pop())
     
    def fire(self):
        """Shoot a bullet.  Bullet is fired from shooter's position and aimed
        along shooter's heading.
        """
        if self.magazine:
            bullet = self.magazine.pop()
            self.fired.append(bullet)
            heading = math.radians(self.shooter.heading())
            bullet.setrate(math.cos(heading) * 0.1, math.sin(heading) * 0.1)
            bullet.goto(self.shooter.xcor(), self.shooter.ycor())
            bullet.showturtle()
 
    def update(self, enemy):
        """Move bullets.  Return True if a bullet collides with the enemy"""
        collides = False
        fired = []
        while self.fired:
            bullet = self.fired.pop()
            if bullet.move():
                self.reload(bullet)
            else:
                if bullet.collide(enemy):
                    collides = True
                    self.reload(bullet)
                else:
                    fired.append(bullet)
        self.fired = fired
        return collides
 
def start_level(level, enemy):
    """Start level.  Enemy starts at top edge of screen"""
    screen.title(f"Level {level+1}.  {lives} lives remaining")
    if enemy:
        enemy.hideturtle()
        enemy.clear()
    gun.reload_all()
    player.goto(0, 0)
    shape, size, rate = enemies[level]
    w, h = turtle.screensize()
    return Sprite(shape, size, rate, pos=(random.randint(-w, w), h))
 
# Player is controlled using keyboard to move and mouse to shoot gun
player = Sprite('turtle')
screen.listen()
screen.onkeypress(lambda: player.step(0, 10), "w")
screen.onkeypress(lambda: player.step(0, -10), "s")
screen.onkeypress(lambda: player.step(-10, 0), "a")
screen.onkeypress(lambda: player.step(10, 0), "d")
screen.onscreenclick(lambda a, b: gun.fire()) 
 
gun = Gun(player, 6)
enemies = (
    ('triangle', 1, (0.03, 0.03)),
    ('square', 2, (-0.06, 0.06)),
    ('arrow', 3, (-0.09, -0.09))
)
level = 0
lives = 3
enemy = start_level(level, None)
while True:
    enemy.move()
    if enemy.collide(player):
        if (lives := lives-1) >= 0:
            enemy = start_level(level, enemy)
        else:
            break
    elif gun.update(enemy):
        if (level := level + 1) < len(enemies):
            enemy = start_level(level, enemy)
        else:
            break
    screen.update()
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020