user11808386
user11808386

Reputation:

Make it so function executes on 2 or more key presses

I'm new to Python and I need some help. How do I make it so a function executes after 2 or more key presses? I'm trying to make a game using turtle similar to Minicraft (a 2D top-down action game) where you can use materials you get from stone and wood to craft a variety of different items. The code isn't finished yet.

Code I need help with:

stone = turtle.Turtle()
stone.shape("circle")
stone.color("gray")
stone.penup()
stone.setposition(-220, 180)
stone.shapesize(stretch_wid=2, stretch_len=3)

def stonebreak():
    stone = turtle.Turtle ()
    stone.shape ("circle")
    stone.color ("gray")
    stone.penup ()
    stone.setposition (-220, 180)
    stone.shapesize (stretch_wid=2, stretch_len=3)
    stone.speed("slow")
    stone.hideturtle()
    stone = 0
    stone += 9
    stonestring = "Stone: %s" % stone
    penstone1.write (stonestring, False, align="left", font=("system", 15, "normal"))
    penstone1.clear()
    penstone1.write (stonestring, False, align="left", font=("system", 15, "normal"))


if isCollision(player, stone):
    wn.onkeypress(stonebreak, "space")
    stone.hideturtle()

Full code:

import turtle
import random
import math
import time
turtle.tracer(5)
score = 0

# Turtles

wn = turtle.Screen()
wn.tracer(0)
wn.bgcolor("black")
wn.title("Catcher")
wn.setup(800, 600)


penwood1 = turtle.Turtle()
penwood1.penup()
penwood1.color("white")
penwood1.hideturtle()
penwood1.goto(-280, 275)
wood = 0
woodstring = "Wood: %s" %wood
penwood1.write(woodstring, False, align ="left", font = ("system", 15, "normal"))

penstone1 = turtle.Turtle()
penstone1.penup()
penstone1.color("white")
penstone1.hideturtle()
penstone1.goto(-200, 275)
stone = 0
stonestring = "Stone: %s" %stone
penstone1.write(stonestring, False, align ="left", font = ("system", 15, "normal"))

player = turtle. Turtle()
player.hideturtle()
player.color("white")
player.shape("triangle")
player.penup()
player.setheading(180)
player.setposition(180, 0)
player.showturtle()
player.penup()
player.speed(0)

pen = turtle.Turtle()
pen.color("white")
pen.shape("circle")
pen.hideturtle()
pen.penup()
pen.setposition(360, 275)
pen.pendown()
pen.setposition(360, -275)
pen.setposition(-360, -275)
pen.setposition(-360, 275)
pen.setposition(360, 275)
pen.shapesize(stretch_wid=3, stretch_len=3)


pen1 = turtle.Turtle()
pen1.color("white")
pen1.shape("circle")
pen1.hideturtle()
pen1.penup()
pen1.goto(-360, 275)
scorestring = "Score: %s" %score
pen1.write(scorestring, False, align = "left", font = ("system", 15, "normal"))


tree = turtle.Turtle()
tree.shape("circle")
tree.color("green")
tree.penup()
tree.setposition(200, 140)

stone1 = turtle.Turtle ()
stone1.shape ("circle")
stone1.color ("gray")
stone1.penup ()
stone1.setposition (-200, 140)
stone1.shapesize (stretch_wid=2, stretch_len=3)
stone1.speed ("slow")

stone = turtle.Turtle()
stone.shape("circle")
stone.color("gray")
stone.penup()
stone.setposition(-220, 180)
stone.shapesize(stretch_wid=2, stretch_len=3)

# ______________________________________________________
treedown = turtle.Turtle()
treedown.shape("circle")
treedown.color("green")
treedown.penup()
treedown.setposition(-250, -140)



# Movement features

def pleft():
    player.setheading(180)
    x = player.xcor()
    x -= 20
    if x < -360:
        x = - 360

    player.setx(x)

def pright():
    player.setheading(0)
    x = player.xcor()
    x += 20
    if x > 360:
        x = + 360

    player.setx(x)

def pdown():
    player.setheading(270)
    y = player.ycor()
    y -= 20
    if y < -275:
        y = - 275

    player.sety(y)

def pup():
    player.setheading(90)
    y = player.ycor()
    y += 20
    if y > 275:
        y = + 275

    player.sety(y)


wn.listen()
wn.onkeypress(pleft, "Left")
wn.onkeypress(pright, "Right")
wn.onkeypress(pup, "Up")
wn.onkeypress(pdown, "Down")



while True:
    wn.update()


    def treebreak():
        tree.speed("slow")
        tree.hideturtle()
        wood = 0
        wood += 2
        woodstring = "Wood: %s" % wood
        penwood1.write (woodstring, False, align="left", font=("system", 15, "normal"))
        penwood1.clear()
        penwood1.write (woodstring, False, align="left", font=("system", 15, "normal"))

        def treebbreak():
            treedown.speed ("slow")
            treedown.hideturtle ()
            wood = 2
            wood += 3
            woodstring = "Wood: %s" % wood
            penwood1.write (woodstring, False, align="left", font=("system", 15, "normal"))
            penwood1.clear ()
            penwood1.write (woodstring, False, align="left", font=("system", 15, "normal"))

        if player.xcor () == -240 and player.ycor () == -140:
            wn.onkeypress (treebbreak, "space")


    if player.xcor() == 180 and player.ycor() == 140:
        wn.onkeypress(treebreak, "space")

    if player.xcor() == 200 and player.ycor() == 120:
        wn.onkeypress(treebreak, "space")

    if player.xcor() == 200 and player.ycor() == 160:
        wn.onkeypress(treebreak, "space")

    if player.xcor() == 221 and player.ycor() == 141:
        wn.onkeypress(treebreak, "space")

    def isCollision(t1, t2):
        distance = math.sqrt(math.pow(t1.xcor()-t2.xcor(),2)+math.pow(t1.ycor()-t2.ycor(),2))
        if distance < 25:
            return True
        else:
            return False

    def stonebreak():
        stone = turtle.Turtle ()
        stone.shape ("circle")
        stone.color ("gray")
        stone.penup ()
        stone.setposition (-220, 180)
        stone.shapesize (stretch_wid=2, stretch_len=3)
        stone.speed("slow")
        stone.hideturtle()
        stone = 0
        stone += 9
        stonestring = "Stone: %s" % stone
        penstone1.write (stonestring, False, align="left", font=("system", 15, "normal"))
        penstone1.clear()
        penstone1.write (stonestring, False, align="left", font=("system", 15, "normal"))


    if isCollision(player, stone):
        wn.onkeypress(stonebreak, "space")
        stone.hideturtle()

    def stone1break():
        stone1 = turtle.Turtle ()
        stone1.shape ("circle")
        stone1.color ("gray")
        stone1.penup ()
        stone1.setposition (-200, 140)
        stone1.shapesize (stretch_wid=2, stretch_len=3)
        stone1.speed("slow")
        stone1.hideturtle()
        stone = 0
        stone += 9
        stonestring = "Stone: %s" % stone
        penstone1.write (stonestring, False, align="left", font=("system", 15, "normal"))
        penstone1.clear()
        penstone1.write (stonestring, False, align="left", font=("system", 15, "normal"))


    if isCollision(player, stone1):
        wn.onkeypress(stone1break, "space")
        stone1.hideturtle()



wn.mainloop()

I'm trying to make it so you gain the materials after 2 or more hits on the targets.

Upvotes: 1

Views: 163

Answers (2)

VVend
VVend

Reputation: 163

First of all, you shouldn't set onkeypress() event handler every time collision occurs. Try to handle it other way:

def checkCollisions():
    if isCollision(player, stone1):
        stone1break()
    if isCollision(player, stone2):
        stone2break()
    ...

wn.onkeypress(checkCollisions, "space")

This code and all of your function defs you should put before your main (while True:) loop.

Then, you will need some state of your game objects. Trivial way is to add variables stone1strength=2, stone2strength=2, ..., and decrease them in coresponding stonebreak() function, clearing the stone after its strength goes below 1.

I like your effort very much. It reminds me my first game programming steps. :)

The next step could be rewriting of your code to store your stone objects into a list and iterate them instead of handling tens of stoneX variables...

Upvotes: 2

cdlane
cdlane

Reputation: 41905

First, I don't see a problem with setting the onkeypress() handler every time a collision is detected. Second, your code is a mess! For example, you have two unrelated global variables with the same name, stone the score value and stone the turtle:

stone = 0
# ...
stone = turtle.Turtle()

You shape and shapesize() the pen turtle which is never visible anyway. And what's going on here:

wood = 2
wood += 3

which happens multiple times, keeping your scores at fixed values rather than increasing. Trying to detect a turtle on an exact position is futile:

 if player.xcor() == 180 and player.ycor() == 140:

As the player moves 20 pixels at a time and this is a floating point plane. And turtle has a distance() method, no reason to reinvent it.

I believe @BoboDarph's state machine suggestion is a good one. Below is my rework, and simplification, of your code that does something simpler. The first time you touch the stone or the tree, it just changes color. After that, you start to earn points:

from turtle import Screen, Turtle

FONT = ('system', 15, 'normal')

# Movement features

def player_left():
    player.setheading(180)

    x = player.xcor() - 20
    if x < -360:
        x = -360

    player.setx(x)

def player_right():
    player.setheading(0)

    x = player.xcor() + 20
    if x > 360:
        x = + 360

    player.setx(x)

def player_down():
    player.setheading(270)

    y = player.ycor() - 20
    if y < -275:
        y = - 275

    player.sety(y)

def player_up():
    player.setheading(90)

    y = player.ycor() + 20
    if y > 275:
        y = + 275

    player.sety(y)

def isCollision(t1, t2):
    return t1.distance(t2) < 25

def tree_touch():
    tree.color('dark green')
    tree.touched = True

def tree_break():
    global wood

    screen.onkeypress(None, 'space')
    tree.color('brown')

    wood += 2

    woodstring = "Wood: %s" % wood
    pen_wood.clear()
    pen_wood.write(woodstring, align='left', font=FONT)

def stone_touch():
    rock.color('gray')
    rock.touched = True

def stone_break():
    global stone

    screen.onkeypress(None, 'space')
    rock.color('light gray')

    stone += 9

    stonestring = "Stone: %s" % stone
    pen_stone.clear()
    pen_stone.write(stonestring, align='left', font=FONT)

# Turtles

screen = Screen()
screen.setup(800, 600)
screen.bgcolor('black')
screen.title("Catcher")
screen.tracer(0)

pen_wood = Turtle()
pen_wood.hideturtle()
pen_wood.color('white')
pen_wood.penup()
pen_wood.goto(-280, 275)

wood = 0
wood_string = "Wood: %s" %wood
pen_wood.write(wood_string, align='left', font=FONT)

pen_stone = Turtle()
pen_stone.hideturtle()
pen_stone.color('white')
pen_stone.penup()
pen_stone.goto(-200, 275)

stone = 0
stone_string = "Stone: %s" %stone
pen_stone.write(stone_string, align='left', font=FONT)

pen = Turtle()
pen.hideturtle()
pen.shape('circle')
pen.color('white')
pen.penup()
pen.setposition(360, 275)
pen.pendown()
pen.setposition(360, -275)
pen.setposition(-360, -275)
pen.setposition(-360, 275)
pen.setposition(360, 275)

rock = Turtle()
rock.shape('circle')
rock.color('dark gray')
rock.penup()
rock.setposition(-220, 180)
rock.shapesize(stretch_wid=2, stretch_len=3)

rock.touched = False

tree = Turtle()
tree.shape('circle')
tree.color('green')
tree.penup()
tree.setposition(200, 140)

tree.touched = False

player = Turtle()
player.hideturtle()
player.shape('triangle')
player.speed('fastest')
player.color('white')
player.setheading(180)
player.penup()
player.setx(180)
player.showturtle()

screen.onkeypress(player_left, 'Left')
screen.onkeypress(player_right, 'Right')
screen.onkeypress(player_up, 'Up')
screen.onkeypress(player_down, 'Down')
screen.listen()

while True:

    if isCollision(player, tree):
        if tree.touched:
            screen.onkeypress(tree_break, "space")
        else:
            screen.onkeypress(tree_touch, "space")
    elif isCollision(player, rock):
        if rock.touched:
            screen.onkeypress(stone_break, "space")
        else:
            screen.onkeypress(stone_touch, "space")
    else:
            screen.onkeypress(None, "space")

    screen.update()

screen.mainloop()  # never reached

TODO

  • Gracefully incorporate multiple trees and stones.

  • Change the fixed value 25 in isCollision() to a value calculated based on the shapesize() of the object.

  • Replace the while True: loop with a function and timed event.

Upvotes: 0

Related Questions