I have some code in main.py:
import pygame, char
def move(char):
#movement code
#friction
if char.xaccel == 0:
if abs(char.xvel) < char.xvelfalloff: char.xvel = 0
elif abs(char.xvel) == char.xvel: char.xvel -= char.xvelfalloff
elif abs(char.xvel) != char.xvel: char.xvel += char.xvelfalloff
#acceleration
char.xvel += char.xaccel
#max speed
if abs(char.xvel) > char.xmaxvel: char.xvel = math.copysign(char.xmaxvel,char.xvel)
#position/collision detection
char.x += char.xvel
char.xaccel = 0
char.yaccel = char.ygravity
char.yvel += char.yaccel
char.y += char.yvel
if char.y < 0: #TODO: more collision detection
char.yvel = 0
char.y = 0
char.onground = True
if char.jumping:
char.yvel = char.jumpstrength
char.jumping = False
char.onground = False
#no more movement code
charObj = char.Char()
charObj = move(charObj)
screen.blit(char.currentanimation, pygame.Rect(char.x, (screen_height-char.y)-char.height, char.width, char.height))
pygame.display.flip()
and some code in char.py:
import pygame
class Char():
spritesheet = pygame.image.load("images/spritesheet.png")
walkanim = []
for i in range(7):
spritesheet.set_clip(pygame.Rect(((sprite_width-7)*i)+3,12,sprite_width,sprite_height))
spritesheetsubsurface = spritesheet.subsurface(spritesheet.get_clip())
walkanim.append(pygame.transform.scale(spritesheetsubsurface, (width, height)))
spritesheet.set_clip(pygame.Rect(0,577,sprite_width,sprite_height))
spritesheetsubsurface = spritesheet.subsurface(spritesheet.get_clip())
idleanim = pygame.transform.scale(spritesheetsubsurface, (width, height))
lastanim = "right"
currentanimation = idleanim
animationframeindex = 0
animationframepause = 6 #how many frames go by between animation frames
animationframetime = 0 #how many frames we have been on the same animation frame
Note that I've cut out everything unrelated here.
So, I get an error when I run this code that says:
Traceback (most recent call last):
File "C:\Users\spng453\scripts\super smash feminist\main.py", line 90, in <module>
screen.blit(char.currentanimation, pygame.Rect(char_x, (screen_height-char_y)-char_height, char_width, char_height))
AttributeError: 'module' object has no attribute 'currentanimation'
I literally have no idea where I could have gone wrong here.
Any help with understanding where this problem stems from would be appreciated.
If you define a class to have an attribute (ie, self.currentanimation), you can access it like so:
charObj = char.Char()
charObj.currentanimation
What you're doing in your code is looking inside the module char, not inside your instance of Char (charObj). The char module has no attribute/variable/etc named currentanimation. But instances of Char do – or, rather, they will once you define an __init__() method in your class definition, and start using self :-)
For more on setting and accessing attributes, take a look at this section of the docs.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 10 months ago.
Improve this question
I'm making my first game in python and pygame. And I found myself in a really strange situation. When I start the game and choose level 1 or 2, everything is working as expected. How ever if I choose level 3, my side-scrolling camera does not work.
Traceback :
Traceback (most recent call last):
File "D:\AMisko-game\main\window.py", line 99, in <module>
game.run()
File "D:\AMisko-game\main\window.py", line 56, in run
self.level.run()
File "D:\AMisko-game\main\level.py", line 192, in run
self.scrollX()
File "D:\AMisko-game\main\level.py", line 104, in scrollX
playerX = player.rect.centerx
AttributeError: 'NoneType' object has no attribute 'rect'
The sidescrolling camera :
def scrollX(self):
player = self.player.sprite
playerX = player.rect.centerx
direcX = player.direc.x
if playerX < screenWidth / 4 and direcX < 0:
self.worldShift = 4
player.speed = 0
elif playerX > screenWidth - (screenWidth / 4) and direcX > 0:
self.worldShift = -4
player.speed = 0
else:
self.worldShift = 0
player.speed = 5
Related things from Level init :
def __init__(self, currentLevel, surface, createOverworld, syringeCollect, healthChange):
self.displaySurface = surface
self.worldShift = 0
self.currX = None
# player
playerLayout = importCsv(gameData['player'])
self.player = pygame.sprite.GroupSingle()
self.goal = pygame.sprite.GroupSingle()
self.playerSetup(playerLayout, healthChange)
I'm really not sure why is it happening. So I looked up the internet and didn't find anything usefull. I figured that probably there's a bug when calling Level class and gathering all the information. And these I have in a seperate file that holds information about each individual level. But as I was checking that, I did not found anything wrong. No misspelling or wrong index. Nothing. I also checked the Player class but I didn't find anything.
Please help.
Edit: When I start the level it just closes my game.
And I'm using 12 files with around 200 lines in each (except support and settings).
Player setup def:
def playerSetup(self, layout, healthChange):
for rowIndex, row in enumerate(layout):
for collIndex, coll in enumerate(row):
x = collIndex * tileSize
y = rowIndex * tileSize
if coll == '0':
sprite = Player((x, y), healthChange)
self.player.add(sprite)
if coll == '1':
setSurface = pygame.image.load(cesty['playerAss'].joinpath('setupend.png')).convert_alpha()
sprite = staticTile(tileSize, x, y, setSurface)
self.goal.add(sprite)
I don't know why you're using GroupSingle, but that's the problem By default, a GroupSingle is created empty. You need to add a sprite to it. Or, skip the group and just create a sprite.
Currently I spent around an hour of debbuging and searching for help. I'm using Tiled program for my maps. And I'm exporting it to csv files. But I did not noticed that I forgot to setup player spawn, so the index was missing in the csv files. That's why it did not work.
I was trying to make some kind of Boxel Rebound game for the micro:bit, and I was coding at the online web editor. It all worked fine, until I tried to implement the jumping. When I start the program, it works fine, and I get my debugging messages in the REPL:
Updating...
Isn't jumping
Updating...
Isn't jumping
Updating...
Isn't jumping
...
But when I press button A, I get
Traceback (most recent call last):
File "main.py", line 57, in <module>
TypeError: 'int' object isn't callable
This is my code:
from microbit import *
def scroll(*args, **kwargs):
for arg in args:
print(arg, **kwargs)
display.scroll(arg)
#scroll('Boxel rebound')
WIDTH = 4
HEIGHT = 4
class Player:
b = 9
def __init__(self):
self.x = 1
self.y = HEIGHT
self.is_jumping = False
self.jump = 0
def update(self):
print('Updating...')
if self.is_jumping:
print(' Is jumping')
self.jump += 1
self.x += 1
else:
print(' Isn\'t jumping')
if self.y > HEIGHT:
self.y += 1
if self.jump >= 2:
self.is_jumping = False
def show(self):
display.set_pixel(
self.x,
self.y,
self.__class__.b
)
def jump(self):
if not self.is_jumping:
self.is_jumping = True
player = Player()
while True:
display.clear()
player.update()
player.show()
if button_b.get_presses() > 0:
break
elif button_a.get_presses() > 0:#button_a.is_pressed():
player.jump() # This raises the error
sleep(200)
display.clear()
In class Player you defined member variable and function named jump. When calling jump method you are trying to call an integer which is not callable type. Just carefully rename one of those two members.
Your Player Object has both an attribute and a method called jump (in your __init__ you have self.jump = 0). This is what your player.jump() is using (while you expect it to use the method) and you obviously cannot call an int as a method.
Change the name of one of the two (attribute or method) and it should work.
This has been asked many times on SO but I have some other bug which I am not seeing:
#!/usr/bin/env python
import rospy
from geometry_msgs.msg import Twist
from rosbook.msg import Detector
def scan_callback(msg):
global closest
global closest_dir
closest_dir = ""
closest = min(msg.forward, msg.left, msg.right, msg.back)
if (msg.forward == closest):
closest_dir = "forward"
elif (msg.left == closets):
closest_dir = "left"
elif (msg.right == closest):
closest_dir = "right"
else:
closest_dir = "back"
# Create a Publisher object. queue_size=1 means that messages that are
# published but not handled by received are lost beyond queue size.
cmd_vel_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)
detect_sub = rospy.Subscriber('detector', Detector, scan_callback)
# Initialize this program as a node
rospy.init_node('pid_demo')
print (rospy.Time.now())
tw_for = Twist()
tw_for.linear.x = 0.3
tw_rot = Twist()
tw_for.angular.z = 0.5
# rate object gets a sleep() method which will sleep 1/10 seconds
rate = rospy.Rate(1)
while not rospy.is_shutdown():
print (rospy.Time.now())
if (closest_dir != "forward"):
cmd_vel_pub.publish(tw_for)
else:
cmd_vel_pub.publish(tw_rot)
rate.sleep()
Gives the error:
0
0
Traceback (most recent call last):
File "/home/pitosalas/catkin_ws/src/rosbook/scripts/pid_driver.py", line 42, in <module>
if (closest_dir != "forward"):
NameError: global name 'closest_dir' is not defined
Those two 0's are interesting. It means that the while loop ran once before the callback was called and triggered the error. I've tried moving the global around, and changing the name but to me this looks totally valid!
Just define variables closest and closest_dir outside of the method scan_callback. Hopeful you wont see the traceback
closest_dir = None
closest = None
def scan_callback(msg): ...
So I do know how to save the class's x,y coordinates but I don't know how to save buildings at the coordinates my player has been at. I'll attempt to make this more clear.
I'm making a text-based. To move your player you either type left,right,up,or down. It will therefore change your x and y accordingly.
Ex: To move up it adds 1 to the y value of the player class. player.yPos += 1 . However if the player goes to the point 0,1 and then 0,2 but moves back down to 0,1 and there was a building at the point 0,1 how do I make sure it's still there when the player goes back? I've been thinking I'll have to store all of the player's x,y movements in to a list. I don't know how to make the positions of that list equal the object that will be there though. If this doesn't make sense I can attempt rewording.
P.S. Please use the most simple logical explanation possible. Generally when I read something on stackoverflow I want to jump off of a cliff with how involved it is. (Basically, dumb it down for me please!)
class player:
Cnuts = 0
statPoints = 0
pStrength = 0
pConstitution = 0
pQuickness = 0
pIntelligence = 0
pStamina = 0
playerName = ''
Weapon = 0
Armour = 0
Shield = 0
inventory = []
xPos = 0
yPos = 0
#Building Code
class Entity:
id = 0
xPos = 0
yPos = 0
name = ''
description = ''
def __init__(self, id, xLocation, yLocation, name, description):
self.xLocation = xLocation
self.yLocation = yLocation
self.id = id
self.name = name
self.description = description
class Structure(Entity):
pass
I haven't decided what goes in to the Structure/Building class because I don't know what else it needs other than what Entity already has. I have another class for monsters that also inherits from Entity which is why I have it.
#Map code
isExploring = True
def Map():
while isExploring == True:
pInput = input('What direction would you like to go?')
if pInput == 'Up':
player.yPos += 1
elif pInput == 'Down':
player.yPos -= 1
elif pInput == 'Left':
player.xPos -= 1
elif pInput == 'Right':
player.xPos += 1
elif pInput == 'Diagonal Left':
player.xPos
player.yPos
elif pInput == 'Diagonal Right':
pass
elif pInput == 'Down Diag Left':
pass
elif pInput == 'Down Diag Right':
pass
Thanks for the help in advance!
I don't see code for a building, but I'm guessing the building will eventually inherit from Entity (Player should also inherit this class). An entity object has self.xLocation and self.yLocation, so this makes it a bit easier to implement a location aware player. So what you do is that the class you make for building has to implement the __hash__ method, so something like this.
class Building(Entity):
def __hash__(self):
return hash(tuple(self.xLocatioin, self.yLocation))
def __eq__(self, other):
return isinstance(other, Building) and hash(self) == hash(other)
The function is called __hash__ because python recognizes this special keyword as meaning that the building object can be placed in a dictionary. So whenever you try to place a Building object in a set or use it as a key for a dictionary, python will automatically call it's __hash__ method, and use that value to determine the position in which to place the object in the set/dictionary. Implementing hash usually means implementing __eq__ which is another magic function that python automatically calls when you compare 2 objects using the == operator.
The player class will then store each building it has visited in a set, which can then be queried to determine if a building has been visited before
class Player(Entity):
def __init__(self, *args):
super.__init__(self, args)
self.visited = set()
self.currLocation = tuple(self.xLocatioin, self.yLocation)
def visit(self, entity):
if not beenHere(entity):
self.visited.add(entity)
self.currLocation = tuple(entity.xLocatioin, entity.yLocation)
def beenHere(self, entity):
return entity in self.visited
And there you have it, now the player object can determine which building it has visited before or not
I dont know why i get this error and it's really annoying... anyone see the problem?
I get this error:
line 66, in <module>
ting.movefigure(ting, "up", 20)
AttributeError: 'int' object has no attribute 'movefigure'
Here is my code:
from tkinter import * import time
def movefigure(self, direction, ammount):
x = 0
y = 0
ammount2 = 0
if direction == "up":
print("Direction = " + ammount)
y = ammount
elif direction == "down":
print("Direction = " + ammount)
ammount2 = ammount - (ammount * 2)
y = ammount2
elif direction == "right" + ammount:
print("Direction = " + ammount)
x = ammount
elif direction == "left":
print("Direction = " + ammount)
ammount2 = ammount - (ammount * 2)
y = ammount2
canvas.move(self, x, y)
root = Tk()
root.title('Canvas')
tingx = 100
tingy = 100
tingxMove = 1
tingyMove = 1
canvas = Canvas(root, width=400, height=400)
ting = canvas.create_rectangle(205, 10, tingx, tingy, tags="Ting", outline='black', fill='gray50')
canvas.pack()
ting.movefigure(ting, "up", 20)
root.mainloop()
You're mixing up functions and methods.
A method is a function defined in a class; it takes a self argument, and you call it on an instance of that class. Like this:
class Spam(object):
def __init__(self, eggs):
self.eggs = eggs
def method(self, beans):
return self.eggs + beans
spam = Spam(20)
print(spam.method(10))
This will print out 30.
But your movefigure is not a method of any class, it's just a regular function. That means it doesn't take a self parameter, and you don't call it with dot syntax. (Of course there's nothing stopping you from calling any parameter self if you want, just like there's nothing stopping you from writing a function called print_with_color that erases a file named /kernel, but it's not a good idea…)
So, you wanted to do this:
def movefigure(rect, direction, ammount):
# all of your existing code, but using rect instead of self
movefigure(ting, "up", 20)