Simple (Very Easy to Make) RPG Game Simulation in Python and Turtle












9














The code creates a very simple/easy RPG game, with 2 classes Jedi and Orc. The data is visualized using turtle. Each class has a method of attack (lightsaber_attack for Jedi), which has an argument that must be either a Jedi or Orc instance. The .health attribute of the attacked one will be reduced by .power of the attacker. If .health is not positive, then the image of the character will disappear. By design, each character can attack itself.



Simulation



luke.lightsaber_attack( orc_1 )
luke.lightsaber_attack( orc_2 )
orc_1.attack( luke )
orc_2.attack( orc_2 )


Questions




  • How can I make the code to be easily understood by teenagers? (in a tutorial)

  • How can I make it more compact?

  • Are there any missing important features of Python's OOP that are important to be explained to students? (other than super and inheritance)


Image Links




  • jedi.gif

  • orc.gif

  • darkorc.gif


  • damaged.gif


Full code



import turtle
import time

jedi_gif = "/home/asus/Arief_tempo/images/random/jedi.gif"
orc_gif = "orc.gif"
darkorc_gif = "darkorc.gif"
damaged_gif = "damaged.gif"

turtle.register_shape( jedi_gif )
turtle.register_shape( orc_gif )
turtle.register_shape( darkorc_gif )
turtle.register_shape( damaged_gif )

class JediLuke:
def __init__(self):
self.power = 300
self.health = 300

self.img = turtle.Turtle( shape = jedi_gif )
self.damaged_img = turtle.Turtle( shape = damaged_gif, visible = False )

self.img.penup()
self.damaged_img.penup()

def lightsaber_attack(self, enemy):
self.img.setpos(enemy.img.pos()[0], enemy.img.pos()[1])
enemy.damaged_img.showturtle()
enemy.health += - self.power
time.sleep(1)

enemy.damaged_img.hideturtle()
if enemy.health < 0:
enemy.img.hideturtle()

self.img.setpos(200, 0)

def change_pos(self, pos):
self.img.setpos(pos[0], pos[1])
self.damaged_img.setpos(pos[0], pos[1] + 150)


class Orc:
def __init__(self, health, gif_image):
self.power = 100
self.health = health

self.img = turtle.Turtle( shape = gif_image )
self.damaged_img = turtle.Turtle( shape = damaged_gif, visible = False )

self.img.penup()
self.damaged_img.penup()

def attack(self, enemy):
current_pos = self.img.pos()
self.img.setpos(enemy.img.pos()[0], enemy.img.pos()[1])
enemy.damaged_img.showturtle()
enemy.health += - self.power

time.sleep(1)

enemy.damaged_img.hideturtle()
if enemy.health < 0:
enemy.img.hideturtle()

self.img.setpos(current_pos[0], current_pos[1])

def change_pos(self, pos):
self.img.setpos(pos[0], pos[1])
self.damaged_img.setpos(pos[0], pos[1] + 150)


luke = JediLuke()
luke.change_pos( [200, 0] )

orc_1 = Orc( health = 400 , gif_image = orc_gif)
orc_1.change_pos( [-200, 100] )

orc_2 = Orc( health = 200, gif_image = darkorc_gif )
orc_2.change_pos( [-200, -100] )









share|improve this question




















  • 4




    As an aside: Luke Skywalker attacking orcs is a jarring mix-up of universes.
    – Reinderien
    Dec 28 '18 at 15:45






  • 2




    I upvoted @Reinderien 's comment, but I also +1 this question because Luke Skywalker. Fighting Orcs.
    – bruglesco
    Dec 28 '18 at 16:10






  • 5




    Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
    – Mast
    Dec 28 '18 at 17:22










  • @Mast noted....
    – Arief Anbiya
    Jan 2 at 13:37










  • why name the attacks differently?
    – Maarten Fabré
    2 days ago
















9














The code creates a very simple/easy RPG game, with 2 classes Jedi and Orc. The data is visualized using turtle. Each class has a method of attack (lightsaber_attack for Jedi), which has an argument that must be either a Jedi or Orc instance. The .health attribute of the attacked one will be reduced by .power of the attacker. If .health is not positive, then the image of the character will disappear. By design, each character can attack itself.



Simulation



luke.lightsaber_attack( orc_1 )
luke.lightsaber_attack( orc_2 )
orc_1.attack( luke )
orc_2.attack( orc_2 )


Questions




  • How can I make the code to be easily understood by teenagers? (in a tutorial)

  • How can I make it more compact?

  • Are there any missing important features of Python's OOP that are important to be explained to students? (other than super and inheritance)


Image Links




  • jedi.gif

  • orc.gif

  • darkorc.gif


  • damaged.gif


Full code



import turtle
import time

jedi_gif = "/home/asus/Arief_tempo/images/random/jedi.gif"
orc_gif = "orc.gif"
darkorc_gif = "darkorc.gif"
damaged_gif = "damaged.gif"

turtle.register_shape( jedi_gif )
turtle.register_shape( orc_gif )
turtle.register_shape( darkorc_gif )
turtle.register_shape( damaged_gif )

class JediLuke:
def __init__(self):
self.power = 300
self.health = 300

self.img = turtle.Turtle( shape = jedi_gif )
self.damaged_img = turtle.Turtle( shape = damaged_gif, visible = False )

self.img.penup()
self.damaged_img.penup()

def lightsaber_attack(self, enemy):
self.img.setpos(enemy.img.pos()[0], enemy.img.pos()[1])
enemy.damaged_img.showturtle()
enemy.health += - self.power
time.sleep(1)

enemy.damaged_img.hideturtle()
if enemy.health < 0:
enemy.img.hideturtle()

self.img.setpos(200, 0)

def change_pos(self, pos):
self.img.setpos(pos[0], pos[1])
self.damaged_img.setpos(pos[0], pos[1] + 150)


class Orc:
def __init__(self, health, gif_image):
self.power = 100
self.health = health

self.img = turtle.Turtle( shape = gif_image )
self.damaged_img = turtle.Turtle( shape = damaged_gif, visible = False )

self.img.penup()
self.damaged_img.penup()

def attack(self, enemy):
current_pos = self.img.pos()
self.img.setpos(enemy.img.pos()[0], enemy.img.pos()[1])
enemy.damaged_img.showturtle()
enemy.health += - self.power

time.sleep(1)

enemy.damaged_img.hideturtle()
if enemy.health < 0:
enemy.img.hideturtle()

self.img.setpos(current_pos[0], current_pos[1])

def change_pos(self, pos):
self.img.setpos(pos[0], pos[1])
self.damaged_img.setpos(pos[0], pos[1] + 150)


luke = JediLuke()
luke.change_pos( [200, 0] )

orc_1 = Orc( health = 400 , gif_image = orc_gif)
orc_1.change_pos( [-200, 100] )

orc_2 = Orc( health = 200, gif_image = darkorc_gif )
orc_2.change_pos( [-200, -100] )









share|improve this question




















  • 4




    As an aside: Luke Skywalker attacking orcs is a jarring mix-up of universes.
    – Reinderien
    Dec 28 '18 at 15:45






  • 2




    I upvoted @Reinderien 's comment, but I also +1 this question because Luke Skywalker. Fighting Orcs.
    – bruglesco
    Dec 28 '18 at 16:10






  • 5




    Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
    – Mast
    Dec 28 '18 at 17:22










  • @Mast noted....
    – Arief Anbiya
    Jan 2 at 13:37










  • why name the attacks differently?
    – Maarten Fabré
    2 days ago














9












9








9


3





The code creates a very simple/easy RPG game, with 2 classes Jedi and Orc. The data is visualized using turtle. Each class has a method of attack (lightsaber_attack for Jedi), which has an argument that must be either a Jedi or Orc instance. The .health attribute of the attacked one will be reduced by .power of the attacker. If .health is not positive, then the image of the character will disappear. By design, each character can attack itself.



Simulation



luke.lightsaber_attack( orc_1 )
luke.lightsaber_attack( orc_2 )
orc_1.attack( luke )
orc_2.attack( orc_2 )


Questions




  • How can I make the code to be easily understood by teenagers? (in a tutorial)

  • How can I make it more compact?

  • Are there any missing important features of Python's OOP that are important to be explained to students? (other than super and inheritance)


Image Links




  • jedi.gif

  • orc.gif

  • darkorc.gif


  • damaged.gif


Full code



import turtle
import time

jedi_gif = "/home/asus/Arief_tempo/images/random/jedi.gif"
orc_gif = "orc.gif"
darkorc_gif = "darkorc.gif"
damaged_gif = "damaged.gif"

turtle.register_shape( jedi_gif )
turtle.register_shape( orc_gif )
turtle.register_shape( darkorc_gif )
turtle.register_shape( damaged_gif )

class JediLuke:
def __init__(self):
self.power = 300
self.health = 300

self.img = turtle.Turtle( shape = jedi_gif )
self.damaged_img = turtle.Turtle( shape = damaged_gif, visible = False )

self.img.penup()
self.damaged_img.penup()

def lightsaber_attack(self, enemy):
self.img.setpos(enemy.img.pos()[0], enemy.img.pos()[1])
enemy.damaged_img.showturtle()
enemy.health += - self.power
time.sleep(1)

enemy.damaged_img.hideturtle()
if enemy.health < 0:
enemy.img.hideturtle()

self.img.setpos(200, 0)

def change_pos(self, pos):
self.img.setpos(pos[0], pos[1])
self.damaged_img.setpos(pos[0], pos[1] + 150)


class Orc:
def __init__(self, health, gif_image):
self.power = 100
self.health = health

self.img = turtle.Turtle( shape = gif_image )
self.damaged_img = turtle.Turtle( shape = damaged_gif, visible = False )

self.img.penup()
self.damaged_img.penup()

def attack(self, enemy):
current_pos = self.img.pos()
self.img.setpos(enemy.img.pos()[0], enemy.img.pos()[1])
enemy.damaged_img.showturtle()
enemy.health += - self.power

time.sleep(1)

enemy.damaged_img.hideturtle()
if enemy.health < 0:
enemy.img.hideturtle()

self.img.setpos(current_pos[0], current_pos[1])

def change_pos(self, pos):
self.img.setpos(pos[0], pos[1])
self.damaged_img.setpos(pos[0], pos[1] + 150)


luke = JediLuke()
luke.change_pos( [200, 0] )

orc_1 = Orc( health = 400 , gif_image = orc_gif)
orc_1.change_pos( [-200, 100] )

orc_2 = Orc( health = 200, gif_image = darkorc_gif )
orc_2.change_pos( [-200, -100] )









share|improve this question















The code creates a very simple/easy RPG game, with 2 classes Jedi and Orc. The data is visualized using turtle. Each class has a method of attack (lightsaber_attack for Jedi), which has an argument that must be either a Jedi or Orc instance. The .health attribute of the attacked one will be reduced by .power of the attacker. If .health is not positive, then the image of the character will disappear. By design, each character can attack itself.



Simulation



luke.lightsaber_attack( orc_1 )
luke.lightsaber_attack( orc_2 )
orc_1.attack( luke )
orc_2.attack( orc_2 )


Questions




  • How can I make the code to be easily understood by teenagers? (in a tutorial)

  • How can I make it more compact?

  • Are there any missing important features of Python's OOP that are important to be explained to students? (other than super and inheritance)


Image Links




  • jedi.gif

  • orc.gif

  • darkorc.gif


  • damaged.gif


Full code



import turtle
import time

jedi_gif = "/home/asus/Arief_tempo/images/random/jedi.gif"
orc_gif = "orc.gif"
darkorc_gif = "darkorc.gif"
damaged_gif = "damaged.gif"

turtle.register_shape( jedi_gif )
turtle.register_shape( orc_gif )
turtle.register_shape( darkorc_gif )
turtle.register_shape( damaged_gif )

class JediLuke:
def __init__(self):
self.power = 300
self.health = 300

self.img = turtle.Turtle( shape = jedi_gif )
self.damaged_img = turtle.Turtle( shape = damaged_gif, visible = False )

self.img.penup()
self.damaged_img.penup()

def lightsaber_attack(self, enemy):
self.img.setpos(enemy.img.pos()[0], enemy.img.pos()[1])
enemy.damaged_img.showturtle()
enemy.health += - self.power
time.sleep(1)

enemy.damaged_img.hideturtle()
if enemy.health < 0:
enemy.img.hideturtle()

self.img.setpos(200, 0)

def change_pos(self, pos):
self.img.setpos(pos[0], pos[1])
self.damaged_img.setpos(pos[0], pos[1] + 150)


class Orc:
def __init__(self, health, gif_image):
self.power = 100
self.health = health

self.img = turtle.Turtle( shape = gif_image )
self.damaged_img = turtle.Turtle( shape = damaged_gif, visible = False )

self.img.penup()
self.damaged_img.penup()

def attack(self, enemy):
current_pos = self.img.pos()
self.img.setpos(enemy.img.pos()[0], enemy.img.pos()[1])
enemy.damaged_img.showturtle()
enemy.health += - self.power

time.sleep(1)

enemy.damaged_img.hideturtle()
if enemy.health < 0:
enemy.img.hideturtle()

self.img.setpos(current_pos[0], current_pos[1])

def change_pos(self, pos):
self.img.setpos(pos[0], pos[1])
self.damaged_img.setpos(pos[0], pos[1] + 150)


luke = JediLuke()
luke.change_pos( [200, 0] )

orc_1 = Orc( health = 400 , gif_image = orc_gif)
orc_1.change_pos( [-200, 100] )

orc_2 = Orc( health = 200, gif_image = darkorc_gif )
orc_2.change_pos( [-200, -100] )






python object-oriented game role-playing-game turtle-graphics






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 2 days ago









Mast

7,43863686




7,43863686










asked Dec 28 '18 at 14:50









Arief Anbiya

512214




512214








  • 4




    As an aside: Luke Skywalker attacking orcs is a jarring mix-up of universes.
    – Reinderien
    Dec 28 '18 at 15:45






  • 2




    I upvoted @Reinderien 's comment, but I also +1 this question because Luke Skywalker. Fighting Orcs.
    – bruglesco
    Dec 28 '18 at 16:10






  • 5




    Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
    – Mast
    Dec 28 '18 at 17:22










  • @Mast noted....
    – Arief Anbiya
    Jan 2 at 13:37










  • why name the attacks differently?
    – Maarten Fabré
    2 days ago














  • 4




    As an aside: Luke Skywalker attacking orcs is a jarring mix-up of universes.
    – Reinderien
    Dec 28 '18 at 15:45






  • 2




    I upvoted @Reinderien 's comment, but I also +1 this question because Luke Skywalker. Fighting Orcs.
    – bruglesco
    Dec 28 '18 at 16:10






  • 5




    Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
    – Mast
    Dec 28 '18 at 17:22










  • @Mast noted....
    – Arief Anbiya
    Jan 2 at 13:37










  • why name the attacks differently?
    – Maarten Fabré
    2 days ago








4




4




As an aside: Luke Skywalker attacking orcs is a jarring mix-up of universes.
– Reinderien
Dec 28 '18 at 15:45




As an aside: Luke Skywalker attacking orcs is a jarring mix-up of universes.
– Reinderien
Dec 28 '18 at 15:45




2




2




I upvoted @Reinderien 's comment, but I also +1 this question because Luke Skywalker. Fighting Orcs.
– bruglesco
Dec 28 '18 at 16:10




I upvoted @Reinderien 's comment, but I also +1 this question because Luke Skywalker. Fighting Orcs.
– bruglesco
Dec 28 '18 at 16:10




5




5




Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
– Mast
Dec 28 '18 at 17:22




Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
– Mast
Dec 28 '18 at 17:22












@Mast noted....
– Arief Anbiya
Jan 2 at 13:37




@Mast noted....
– Arief Anbiya
Jan 2 at 13:37












why name the attacks differently?
– Maarten Fabré
2 days ago




why name the attacks differently?
– Maarten Fabré
2 days ago










4 Answers
4






active

oldest

votes


















9














jedi_gif = "/home/asus/Arief_tempo/images/random/jedi.gif"


It's unclear why this image has an absolute path but no others do. They should probably all be relative, as the other three are.



Especially if this is for a tutorial, you need to add docstrings to all of your functions.



This:



self.img.setpos(enemy.img.pos()[0], enemy.img.pos()[1])


can use argument expansion, i.e.:



self.img.setpos(*enemy.img.pos())


That pattern can be used elsewhere you're indexing into the position.



This:



enemy.health += - self.power


should be



enemy.health -= self.power





share|improve this answer





















  • Thanks. Why need docstrings? the functions will be explained in class. If I use f(*pos) then I need to explain further about function to the kids (which makes the subject a bit more tedious to them), but using f(pos[0], pos[1]) would be more obvious.
    – Arief Anbiya
    Dec 29 '18 at 13:01










  • "Explaining it [presumably verbally] in class" is not good enough. The code should document itself. You should be able to hand a copy to a programmer who has not attended your class and have some reasonable expectation that they'll understand what's going on.
    – Reinderien
    Dec 29 '18 at 16:59



















5














Just a note of something that was particularly jarring when viewing your code; for stylistic reasons, you shouldn't have spaces on either side of the arguments:



turtle.register_shape( jedi_gif )


Instead you want:



turtle.register_shape(jedi_gif)


This is covered in PEP 8 in the section Whitespace in Expressions and Statements. It's good to follow PEP 8 because it makes it easier for others (and in the long run, yourself) to read your code:






share|improve this answer





























    2














    One guiding principle in programming is to write DRY code, Don't Repeat Yourself. Your JediLuke class and your Orc class are almost the same. Since you are already teaching about classes, you should also teach about inheritance (maybe later, but eventually).



    import turtle
    import time

    class Entity:
    def __init__(self, power, health, img, damaged_img, *position):
    self.power = power
    self.health = health
    self.img = turtle.Turtle(shape=img)
    self.damaged_img = turtle.Turtle(shape=damaged_img, visible=False)

    self.img.penup()
    self.damaged_img.penup()
    self.set_position(*position)

    def attack(self, enemy):
    """Attack an enemy"""
    current_pos = self.img.pos()
    self.img.setpos(*enemy.img.pos())
    enemy.damaged(self.power)
    self.img.setpos(*current_pos)

    def damaged(self, power):
    """Take damage from `power`"""
    self.damaged_img.showturtle()
    self.health -= power
    time.sleep(1)
    self.damaged_img.hideturtle()
    if self.health <= 0:
    self.img.hideturtle()

    def set_position(self, pos):
    self.img.setpos(*pos)
    self.damaged_img.setpos(pos[0], pos[1] + 150)


    class Jedi(Entity):
    def lightsaber_attack(self, enemy):
    super().attack(enemy)

    attack = None # to ensure it cannot be called...


    class Orc(Entity):
    pass


    if __name__ == "__main__":

    jedi_gif = "jedi.gif"
    orc_gif = "orc.gif"
    darkorc_gif = "darkorc.gif"
    damaged_gif = "damaged.gif"

    turtle.register_shape(jedi_gif)
    turtle.register_shape(orc_gif)
    turtle.register_shape(darkorc_gif)
    turtle.register_shape(damaged_gif)

    luke = Jedi(200, 0)
    orc_1 = Orc(400, orc_gif, -200, 100)
    orc_2 = Orc(200, darkorc_gif, -200, -100)


    This also has the calling code under an if __name__ == "__main__" guard to allow importing from this script and the whitespace fixed according to PEP8.






    share|improve this answer































      0














      I just wanted to add use os path for cross compatibility with other os's. Since mac uses a "/", and windows ""



      otherwise if you copy your code to windows and run the script you will get an error saying it's not a valid directory



      use



      from os import path

      path.join("Directory1", "Directory2", "filename.gif")
      # Equal to "Directory1/Directory2/filename.gif
      # or "Directory1Directory2filename.gif





      share|improve this answer








      New contributor




      Davidhall is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.


















        Your Answer





        StackExchange.ifUsing("editor", function () {
        return StackExchange.using("mathjaxEditing", function () {
        StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
        StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
        });
        });
        }, "mathjax-editing");

        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "196"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: false,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: null,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210494%2fsimple-very-easy-to-make-rpg-game-simulation-in-python-and-turtle%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        4 Answers
        4






        active

        oldest

        votes








        4 Answers
        4






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        9














        jedi_gif = "/home/asus/Arief_tempo/images/random/jedi.gif"


        It's unclear why this image has an absolute path but no others do. They should probably all be relative, as the other three are.



        Especially if this is for a tutorial, you need to add docstrings to all of your functions.



        This:



        self.img.setpos(enemy.img.pos()[0], enemy.img.pos()[1])


        can use argument expansion, i.e.:



        self.img.setpos(*enemy.img.pos())


        That pattern can be used elsewhere you're indexing into the position.



        This:



        enemy.health += - self.power


        should be



        enemy.health -= self.power





        share|improve this answer





















        • Thanks. Why need docstrings? the functions will be explained in class. If I use f(*pos) then I need to explain further about function to the kids (which makes the subject a bit more tedious to them), but using f(pos[0], pos[1]) would be more obvious.
          – Arief Anbiya
          Dec 29 '18 at 13:01










        • "Explaining it [presumably verbally] in class" is not good enough. The code should document itself. You should be able to hand a copy to a programmer who has not attended your class and have some reasonable expectation that they'll understand what's going on.
          – Reinderien
          Dec 29 '18 at 16:59
















        9














        jedi_gif = "/home/asus/Arief_tempo/images/random/jedi.gif"


        It's unclear why this image has an absolute path but no others do. They should probably all be relative, as the other three are.



        Especially if this is for a tutorial, you need to add docstrings to all of your functions.



        This:



        self.img.setpos(enemy.img.pos()[0], enemy.img.pos()[1])


        can use argument expansion, i.e.:



        self.img.setpos(*enemy.img.pos())


        That pattern can be used elsewhere you're indexing into the position.



        This:



        enemy.health += - self.power


        should be



        enemy.health -= self.power





        share|improve this answer





















        • Thanks. Why need docstrings? the functions will be explained in class. If I use f(*pos) then I need to explain further about function to the kids (which makes the subject a bit more tedious to them), but using f(pos[0], pos[1]) would be more obvious.
          – Arief Anbiya
          Dec 29 '18 at 13:01










        • "Explaining it [presumably verbally] in class" is not good enough. The code should document itself. You should be able to hand a copy to a programmer who has not attended your class and have some reasonable expectation that they'll understand what's going on.
          – Reinderien
          Dec 29 '18 at 16:59














        9












        9








        9






        jedi_gif = "/home/asus/Arief_tempo/images/random/jedi.gif"


        It's unclear why this image has an absolute path but no others do. They should probably all be relative, as the other three are.



        Especially if this is for a tutorial, you need to add docstrings to all of your functions.



        This:



        self.img.setpos(enemy.img.pos()[0], enemy.img.pos()[1])


        can use argument expansion, i.e.:



        self.img.setpos(*enemy.img.pos())


        That pattern can be used elsewhere you're indexing into the position.



        This:



        enemy.health += - self.power


        should be



        enemy.health -= self.power





        share|improve this answer












        jedi_gif = "/home/asus/Arief_tempo/images/random/jedi.gif"


        It's unclear why this image has an absolute path but no others do. They should probably all be relative, as the other three are.



        Especially if this is for a tutorial, you need to add docstrings to all of your functions.



        This:



        self.img.setpos(enemy.img.pos()[0], enemy.img.pos()[1])


        can use argument expansion, i.e.:



        self.img.setpos(*enemy.img.pos())


        That pattern can be used elsewhere you're indexing into the position.



        This:



        enemy.health += - self.power


        should be



        enemy.health -= self.power






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Dec 28 '18 at 15:59









        Reinderien

        3,842821




        3,842821












        • Thanks. Why need docstrings? the functions will be explained in class. If I use f(*pos) then I need to explain further about function to the kids (which makes the subject a bit more tedious to them), but using f(pos[0], pos[1]) would be more obvious.
          – Arief Anbiya
          Dec 29 '18 at 13:01










        • "Explaining it [presumably verbally] in class" is not good enough. The code should document itself. You should be able to hand a copy to a programmer who has not attended your class and have some reasonable expectation that they'll understand what's going on.
          – Reinderien
          Dec 29 '18 at 16:59


















        • Thanks. Why need docstrings? the functions will be explained in class. If I use f(*pos) then I need to explain further about function to the kids (which makes the subject a bit more tedious to them), but using f(pos[0], pos[1]) would be more obvious.
          – Arief Anbiya
          Dec 29 '18 at 13:01










        • "Explaining it [presumably verbally] in class" is not good enough. The code should document itself. You should be able to hand a copy to a programmer who has not attended your class and have some reasonable expectation that they'll understand what's going on.
          – Reinderien
          Dec 29 '18 at 16:59
















        Thanks. Why need docstrings? the functions will be explained in class. If I use f(*pos) then I need to explain further about function to the kids (which makes the subject a bit more tedious to them), but using f(pos[0], pos[1]) would be more obvious.
        – Arief Anbiya
        Dec 29 '18 at 13:01




        Thanks. Why need docstrings? the functions will be explained in class. If I use f(*pos) then I need to explain further about function to the kids (which makes the subject a bit more tedious to them), but using f(pos[0], pos[1]) would be more obvious.
        – Arief Anbiya
        Dec 29 '18 at 13:01












        "Explaining it [presumably verbally] in class" is not good enough. The code should document itself. You should be able to hand a copy to a programmer who has not attended your class and have some reasonable expectation that they'll understand what's going on.
        – Reinderien
        Dec 29 '18 at 16:59




        "Explaining it [presumably verbally] in class" is not good enough. The code should document itself. You should be able to hand a copy to a programmer who has not attended your class and have some reasonable expectation that they'll understand what's going on.
        – Reinderien
        Dec 29 '18 at 16:59













        5














        Just a note of something that was particularly jarring when viewing your code; for stylistic reasons, you shouldn't have spaces on either side of the arguments:



        turtle.register_shape( jedi_gif )


        Instead you want:



        turtle.register_shape(jedi_gif)


        This is covered in PEP 8 in the section Whitespace in Expressions and Statements. It's good to follow PEP 8 because it makes it easier for others (and in the long run, yourself) to read your code:






        share|improve this answer


























          5














          Just a note of something that was particularly jarring when viewing your code; for stylistic reasons, you shouldn't have spaces on either side of the arguments:



          turtle.register_shape( jedi_gif )


          Instead you want:



          turtle.register_shape(jedi_gif)


          This is covered in PEP 8 in the section Whitespace in Expressions and Statements. It's good to follow PEP 8 because it makes it easier for others (and in the long run, yourself) to read your code:






          share|improve this answer
























            5












            5








            5






            Just a note of something that was particularly jarring when viewing your code; for stylistic reasons, you shouldn't have spaces on either side of the arguments:



            turtle.register_shape( jedi_gif )


            Instead you want:



            turtle.register_shape(jedi_gif)


            This is covered in PEP 8 in the section Whitespace in Expressions and Statements. It's good to follow PEP 8 because it makes it easier for others (and in the long run, yourself) to read your code:






            share|improve this answer












            Just a note of something that was particularly jarring when viewing your code; for stylistic reasons, you shouldn't have spaces on either side of the arguments:



            turtle.register_shape( jedi_gif )


            Instead you want:



            turtle.register_shape(jedi_gif)


            This is covered in PEP 8 in the section Whitespace in Expressions and Statements. It's good to follow PEP 8 because it makes it easier for others (and in the long run, yourself) to read your code:







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Dec 28 '18 at 17:39









            Graham

            970113




            970113























                2














                One guiding principle in programming is to write DRY code, Don't Repeat Yourself. Your JediLuke class and your Orc class are almost the same. Since you are already teaching about classes, you should also teach about inheritance (maybe later, but eventually).



                import turtle
                import time

                class Entity:
                def __init__(self, power, health, img, damaged_img, *position):
                self.power = power
                self.health = health
                self.img = turtle.Turtle(shape=img)
                self.damaged_img = turtle.Turtle(shape=damaged_img, visible=False)

                self.img.penup()
                self.damaged_img.penup()
                self.set_position(*position)

                def attack(self, enemy):
                """Attack an enemy"""
                current_pos = self.img.pos()
                self.img.setpos(*enemy.img.pos())
                enemy.damaged(self.power)
                self.img.setpos(*current_pos)

                def damaged(self, power):
                """Take damage from `power`"""
                self.damaged_img.showturtle()
                self.health -= power
                time.sleep(1)
                self.damaged_img.hideturtle()
                if self.health <= 0:
                self.img.hideturtle()

                def set_position(self, pos):
                self.img.setpos(*pos)
                self.damaged_img.setpos(pos[0], pos[1] + 150)


                class Jedi(Entity):
                def lightsaber_attack(self, enemy):
                super().attack(enemy)

                attack = None # to ensure it cannot be called...


                class Orc(Entity):
                pass


                if __name__ == "__main__":

                jedi_gif = "jedi.gif"
                orc_gif = "orc.gif"
                darkorc_gif = "darkorc.gif"
                damaged_gif = "damaged.gif"

                turtle.register_shape(jedi_gif)
                turtle.register_shape(orc_gif)
                turtle.register_shape(darkorc_gif)
                turtle.register_shape(damaged_gif)

                luke = Jedi(200, 0)
                orc_1 = Orc(400, orc_gif, -200, 100)
                orc_2 = Orc(200, darkorc_gif, -200, -100)


                This also has the calling code under an if __name__ == "__main__" guard to allow importing from this script and the whitespace fixed according to PEP8.






                share|improve this answer




























                  2














                  One guiding principle in programming is to write DRY code, Don't Repeat Yourself. Your JediLuke class and your Orc class are almost the same. Since you are already teaching about classes, you should also teach about inheritance (maybe later, but eventually).



                  import turtle
                  import time

                  class Entity:
                  def __init__(self, power, health, img, damaged_img, *position):
                  self.power = power
                  self.health = health
                  self.img = turtle.Turtle(shape=img)
                  self.damaged_img = turtle.Turtle(shape=damaged_img, visible=False)

                  self.img.penup()
                  self.damaged_img.penup()
                  self.set_position(*position)

                  def attack(self, enemy):
                  """Attack an enemy"""
                  current_pos = self.img.pos()
                  self.img.setpos(*enemy.img.pos())
                  enemy.damaged(self.power)
                  self.img.setpos(*current_pos)

                  def damaged(self, power):
                  """Take damage from `power`"""
                  self.damaged_img.showturtle()
                  self.health -= power
                  time.sleep(1)
                  self.damaged_img.hideturtle()
                  if self.health <= 0:
                  self.img.hideturtle()

                  def set_position(self, pos):
                  self.img.setpos(*pos)
                  self.damaged_img.setpos(pos[0], pos[1] + 150)


                  class Jedi(Entity):
                  def lightsaber_attack(self, enemy):
                  super().attack(enemy)

                  attack = None # to ensure it cannot be called...


                  class Orc(Entity):
                  pass


                  if __name__ == "__main__":

                  jedi_gif = "jedi.gif"
                  orc_gif = "orc.gif"
                  darkorc_gif = "darkorc.gif"
                  damaged_gif = "damaged.gif"

                  turtle.register_shape(jedi_gif)
                  turtle.register_shape(orc_gif)
                  turtle.register_shape(darkorc_gif)
                  turtle.register_shape(damaged_gif)

                  luke = Jedi(200, 0)
                  orc_1 = Orc(400, orc_gif, -200, 100)
                  orc_2 = Orc(200, darkorc_gif, -200, -100)


                  This also has the calling code under an if __name__ == "__main__" guard to allow importing from this script and the whitespace fixed according to PEP8.






                  share|improve this answer


























                    2












                    2








                    2






                    One guiding principle in programming is to write DRY code, Don't Repeat Yourself. Your JediLuke class and your Orc class are almost the same. Since you are already teaching about classes, you should also teach about inheritance (maybe later, but eventually).



                    import turtle
                    import time

                    class Entity:
                    def __init__(self, power, health, img, damaged_img, *position):
                    self.power = power
                    self.health = health
                    self.img = turtle.Turtle(shape=img)
                    self.damaged_img = turtle.Turtle(shape=damaged_img, visible=False)

                    self.img.penup()
                    self.damaged_img.penup()
                    self.set_position(*position)

                    def attack(self, enemy):
                    """Attack an enemy"""
                    current_pos = self.img.pos()
                    self.img.setpos(*enemy.img.pos())
                    enemy.damaged(self.power)
                    self.img.setpos(*current_pos)

                    def damaged(self, power):
                    """Take damage from `power`"""
                    self.damaged_img.showturtle()
                    self.health -= power
                    time.sleep(1)
                    self.damaged_img.hideturtle()
                    if self.health <= 0:
                    self.img.hideturtle()

                    def set_position(self, pos):
                    self.img.setpos(*pos)
                    self.damaged_img.setpos(pos[0], pos[1] + 150)


                    class Jedi(Entity):
                    def lightsaber_attack(self, enemy):
                    super().attack(enemy)

                    attack = None # to ensure it cannot be called...


                    class Orc(Entity):
                    pass


                    if __name__ == "__main__":

                    jedi_gif = "jedi.gif"
                    orc_gif = "orc.gif"
                    darkorc_gif = "darkorc.gif"
                    damaged_gif = "damaged.gif"

                    turtle.register_shape(jedi_gif)
                    turtle.register_shape(orc_gif)
                    turtle.register_shape(darkorc_gif)
                    turtle.register_shape(damaged_gif)

                    luke = Jedi(200, 0)
                    orc_1 = Orc(400, orc_gif, -200, 100)
                    orc_2 = Orc(200, darkorc_gif, -200, -100)


                    This also has the calling code under an if __name__ == "__main__" guard to allow importing from this script and the whitespace fixed according to PEP8.






                    share|improve this answer














                    One guiding principle in programming is to write DRY code, Don't Repeat Yourself. Your JediLuke class and your Orc class are almost the same. Since you are already teaching about classes, you should also teach about inheritance (maybe later, but eventually).



                    import turtle
                    import time

                    class Entity:
                    def __init__(self, power, health, img, damaged_img, *position):
                    self.power = power
                    self.health = health
                    self.img = turtle.Turtle(shape=img)
                    self.damaged_img = turtle.Turtle(shape=damaged_img, visible=False)

                    self.img.penup()
                    self.damaged_img.penup()
                    self.set_position(*position)

                    def attack(self, enemy):
                    """Attack an enemy"""
                    current_pos = self.img.pos()
                    self.img.setpos(*enemy.img.pos())
                    enemy.damaged(self.power)
                    self.img.setpos(*current_pos)

                    def damaged(self, power):
                    """Take damage from `power`"""
                    self.damaged_img.showturtle()
                    self.health -= power
                    time.sleep(1)
                    self.damaged_img.hideturtle()
                    if self.health <= 0:
                    self.img.hideturtle()

                    def set_position(self, pos):
                    self.img.setpos(*pos)
                    self.damaged_img.setpos(pos[0], pos[1] + 150)


                    class Jedi(Entity):
                    def lightsaber_attack(self, enemy):
                    super().attack(enemy)

                    attack = None # to ensure it cannot be called...


                    class Orc(Entity):
                    pass


                    if __name__ == "__main__":

                    jedi_gif = "jedi.gif"
                    orc_gif = "orc.gif"
                    darkorc_gif = "darkorc.gif"
                    damaged_gif = "damaged.gif"

                    turtle.register_shape(jedi_gif)
                    turtle.register_shape(orc_gif)
                    turtle.register_shape(darkorc_gif)
                    turtle.register_shape(damaged_gif)

                    luke = Jedi(200, 0)
                    orc_1 = Orc(400, orc_gif, -200, 100)
                    orc_2 = Orc(200, darkorc_gif, -200, -100)


                    This also has the calling code under an if __name__ == "__main__" guard to allow importing from this script and the whitespace fixed according to PEP8.







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Dec 31 '18 at 13:18

























                    answered Dec 30 '18 at 13:16









                    Graipher

                    23.6k53585




                    23.6k53585























                        0














                        I just wanted to add use os path for cross compatibility with other os's. Since mac uses a "/", and windows ""



                        otherwise if you copy your code to windows and run the script you will get an error saying it's not a valid directory



                        use



                        from os import path

                        path.join("Directory1", "Directory2", "filename.gif")
                        # Equal to "Directory1/Directory2/filename.gif
                        # or "Directory1Directory2filename.gif





                        share|improve this answer








                        New contributor




                        Davidhall is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                        Check out our Code of Conduct.























                          0














                          I just wanted to add use os path for cross compatibility with other os's. Since mac uses a "/", and windows ""



                          otherwise if you copy your code to windows and run the script you will get an error saying it's not a valid directory



                          use



                          from os import path

                          path.join("Directory1", "Directory2", "filename.gif")
                          # Equal to "Directory1/Directory2/filename.gif
                          # or "Directory1Directory2filename.gif





                          share|improve this answer








                          New contributor




                          Davidhall is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                          Check out our Code of Conduct.





















                            0












                            0








                            0






                            I just wanted to add use os path for cross compatibility with other os's. Since mac uses a "/", and windows ""



                            otherwise if you copy your code to windows and run the script you will get an error saying it's not a valid directory



                            use



                            from os import path

                            path.join("Directory1", "Directory2", "filename.gif")
                            # Equal to "Directory1/Directory2/filename.gif
                            # or "Directory1Directory2filename.gif





                            share|improve this answer








                            New contributor




                            Davidhall is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.









                            I just wanted to add use os path for cross compatibility with other os's. Since mac uses a "/", and windows ""



                            otherwise if you copy your code to windows and run the script you will get an error saying it's not a valid directory



                            use



                            from os import path

                            path.join("Directory1", "Directory2", "filename.gif")
                            # Equal to "Directory1/Directory2/filename.gif
                            # or "Directory1Directory2filename.gif






                            share|improve this answer








                            New contributor




                            Davidhall is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.









                            share|improve this answer



                            share|improve this answer






                            New contributor




                            Davidhall is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.









                            answered 2 days ago









                            Davidhall

                            11




                            11




                            New contributor




                            Davidhall is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.





                            New contributor





                            Davidhall is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.






                            Davidhall is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                            Check out our Code of Conduct.






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Code Review Stack Exchange!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                Use MathJax to format equations. MathJax reference.


                                To learn more, see our tips on writing great answers.





                                Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                Please pay close attention to the following guidance:


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210494%2fsimple-very-easy-to-make-rpg-game-simulation-in-python-and-turtle%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

                                ComboBox Display Member on multiple fields

                                Is it possible to collect Nectar points via Trainline?