python - Bullets shooting from wrong position after player moved in small "Space Invaders" game - Stack Overfl
- c - Solaris 10 make Error code 1 Fatal Error when trying to build python 2.7.16 - Stack Overflow 推荐度:
- javascript - How to dismiss a phonegap notification programmatically - Stack Overflow 推荐度:
- javascript - Get the JSON objects that are not present in another array - Stack Overflow 推荐度:
- javascript - VS 2015 Angular 2 import modules cannot be resolved - Stack Overflow 推荐度:
- javascript - Type 'undefined' is not assignable to type 'menuItemProps[]' - Stack Overflow 推荐度:
- 相关推荐
I'm a beginner in Python and trying to code a game such as Space Invaders.
I created everything but when I move my character and fire, the bullet will remain shooting from the character's original position.
I need it the be shot from the character's actual position at every time.
main.py
from turtle import Turtle, Screen
from player import Player
from bullet import Bullet, BULLET_SPEED
turtle = Turtle()
screen = Screen()
screen.setup(width=800, height=800)
screen.title("Shmup Test")
screen.bgcolor("black")
player = Player()
bullet = Bullet()
screen.listen()
screen.onkey(key="Up", fun=player.go_up)
screen.onkey(key="Down", fun=player.go_down)
screen.onkey(key="Left", fun=player.go_left)
screen.onkey(key="Right", fun=player.go_right)
screen.onkey(key="space", fun=bullet.fire_bullet)
while True:
bullet.forward(BULLET_SPEED)
player.py
from turtle import Turtle, Screen
MOVE_DISTANCE = 10
screen = Screen()
class Player(Turtle):
def __init__(self):
super().__init__()
self.image = "penguin.gif"
screen.register_shape(self.image)
self.shape(self.image)
self.penup()
self.speed(0)
self.setposition(0, -180)
self.setheading(90)
def go_up(self):
new_y = self.ycor() + MOVE_DISTANCE
if new_y > 330:
new_y = 330
self.goto(self.xcor(), new_y)
def go_down(self):
new_y = self.ycor() - MOVE_DISTANCE
if new_y < -330:
new_y = -330
self.goto(self.xcor(), new_y)
def go_left(self):
new_x = self.xcor() - MOVE_DISTANCE
if new_x < -330:
new_x = -330
self.goto(new_x, self.ycor())
def go_right(self):
new_x = self.xcor() + MOVE_DISTANCE
if new_x > 330:
new_x = 330
self.goto(new_x, self.ycor())
bullet.py
from turtle import Turtle, Screen
from player import Player
BULLET_SPEED = 10
self = Turtle()
player = Player()
screen = Screen()
class Bullet(Turtle):
def __init__(self):
super().__init__()
self.color("red")
self.shape("circle")
self.penup()
self.speed(0)
self.setposition(player.xcor(), player.ycor())
self.setheading(90)
self.shapesize(.5, .5)
self.hideturtle()
def fire_bullet(self):
x_pos = player.xcor()
y_pos = player.ycor()
self.setposition(x_pos, y_pos)
self.showturtle()
I'm a beginner in Python and trying to code a game such as Space Invaders.
I created everything but when I move my character and fire, the bullet will remain shooting from the character's original position.
I need it the be shot from the character's actual position at every time.
main.py
from turtle import Turtle, Screen
from player import Player
from bullet import Bullet, BULLET_SPEED
turtle = Turtle()
screen = Screen()
screen.setup(width=800, height=800)
screen.title("Shmup Test")
screen.bgcolor("black")
player = Player()
bullet = Bullet()
screen.listen()
screen.onkey(key="Up", fun=player.go_up)
screen.onkey(key="Down", fun=player.go_down)
screen.onkey(key="Left", fun=player.go_left)
screen.onkey(key="Right", fun=player.go_right)
screen.onkey(key="space", fun=bullet.fire_bullet)
while True:
bullet.forward(BULLET_SPEED)
player.py
from turtle import Turtle, Screen
MOVE_DISTANCE = 10
screen = Screen()
class Player(Turtle):
def __init__(self):
super().__init__()
self.image = "penguin.gif"
screen.register_shape(self.image)
self.shape(self.image)
self.penup()
self.speed(0)
self.setposition(0, -180)
self.setheading(90)
def go_up(self):
new_y = self.ycor() + MOVE_DISTANCE
if new_y > 330:
new_y = 330
self.goto(self.xcor(), new_y)
def go_down(self):
new_y = self.ycor() - MOVE_DISTANCE
if new_y < -330:
new_y = -330
self.goto(self.xcor(), new_y)
def go_left(self):
new_x = self.xcor() - MOVE_DISTANCE
if new_x < -330:
new_x = -330
self.goto(new_x, self.ycor())
def go_right(self):
new_x = self.xcor() + MOVE_DISTANCE
if new_x > 330:
new_x = 330
self.goto(new_x, self.ycor())
bullet.py
from turtle import Turtle, Screen
from player import Player
BULLET_SPEED = 10
self = Turtle()
player = Player()
screen = Screen()
class Bullet(Turtle):
def __init__(self):
super().__init__()
self.color("red")
self.shape("circle")
self.penup()
self.speed(0)
self.setposition(player.xcor(), player.ycor())
self.setheading(90)
self.shapesize(.5, .5)
self.hideturtle()
def fire_bullet(self):
x_pos = player.xcor()
y_pos = player.ycor()
self.setposition(x_pos, y_pos)
self.showturtle()
Share
Improve this question
edited yesterday
ggorlen
56.5k7 gold badges109 silver badges148 bronze badges
asked yesterday
Needle_KaneNeedle_Kane
311 silver badge1 bronze badge
New contributor
Needle_Kane is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
2 Answers
Reset to default 3The Bullet
class uses a separate instance of the Player
class to determine from where to shoot.
So it does not notice if the Player
instance used in main.py has moved.
You should use only one instance of Player
that is shared between main.py and Bullet
. A typical way to achieve that would be to create it in main.py and pass it as argument to Bullet
.
There are several changes needed:
In main.py:
player = Player()
bullet = Bullet()
becomes
player = Player()
bullet = Bullet(player)
In bullet.py:
player = Player()
class Bullet(Turtle):
def __init__(self):
super().__init__()
becomes
class Bullet(Turtle):
def __init__(self, player):
super().__init__()
self.player = player
and
def fire_bullet(self):
x_pos = player.xcor()
y_pos = player.ycor()
becomes
def fire_bullet(self):
x_pos = self.player.xcor()
y_pos = self.player.ycor()
This answer nicely identifies the cause of your main problem and provides a quick fix, but beyond that, there are a number of serious design flaws that will make it difficult for you to move forward with this game in any sensible capacity.
I'll defer to other posts below for deeper explanations, but suffice to say your event loop won't let you move multiple turtles in real-time very easily. You'll likely want to disable the internal turtle event loop with screen.tracer(0)
and use a custom event loop that will let you run only one screen update per frame, after repositioning all entities. This effectively lets you move multiple entities at once, enabling real-time animation. Without that, each turtle will need to complete its movement in a single-threaded manner before the next turtle can move, which is basically a non-starter.
Here's the suggested rewrite:
from turtle import Turtle, Screen
class Player:
def __init__(self):
self.speed = 10
self.bullets = []
self.pen = Turtle()
self.pen.penup()
def update(self):
for bullet in self.bullets:
bullet.move()
def forward(self):
self.pen.forward(self.speed)
def left(self):
self.pen.left(self.speed)
def right(self):
self.pen.right(self.speed)
def fire(self):
pen = self.pen
bullet = Bullet(pen.xcor(), pen.ycor(), pen.heading())
self.bullets.append(bullet)
class Bullet:
def __init__(self, x, y, heading):
self.speed = 15
self.pen = pen = Turtle()
pen.penup()
pen.goto(x, y)
pen.shape("circle")
pen.setheading(heading)
pen.shapesize(0.3, 0.3)
def move(self):
self.pen.forward(self.speed)
screen = Screen()
screen.tracer(0)
player = Player()
frame_delay_ms = 1000 // 30
actions = dict(
Left=player.left,
Right=player.right,
Up=player.forward,
space=player.fire,
)
keys_pressed = set()
def bind(key):
screen.onkeypress(lambda: keys_pressed.add(key), key)
screen.onkeyrelease(lambda: keys_pressed.remove(key), key)
for key in actions:
bind(key)
def tick():
for action in list(keys_pressed):
actions[action]()
player.update()
screen.update()
screen.ontimer(tick, frame_delay_ms)
screen.listen()
tick()
screen.exitonclick()
I've kept this in a single file for simplicity, but if you do break it out again, don't instantiate anything in your class files in the global scope. All instantiation will happen in the shared main.py file, other than bullets, which the player imports and instantiates when shot (you could make the bullet list global if you want, but attaching bullets to players makes sense--the bullets belong to a particular player).
See these threads for motivation for the changes:
- How to bind several key presses together in turtle graphics?
- How to create a subclass in python that is inherited from turtle Module
Note that this still isn't a perfect design--turtles can't be de-allocated, so you'll need an object pool for your bullets to recycle them when they hit an object or leave the screen. The game will slow down as you shoot more bullets, which continue moving forever once shot.
You'll probably also want a cooldown period for each shot to avoid too much spamming.
Turtle is generally not a good tool for making real-time games, but this should give you an acceptable real-time game set up for educational purposes.
- AMD、英特尔等开始疏远Windows
- powershell - Windows AutoPilot - Set Auto Login - Stack Overflow
- php - Laravel RouteServiceProvider missing in appProviders directory - Stack Overflow
- soa - How to use a variable in a composite or wsdl, as I need to have this variable per environment? - Stack Overflow
- c# - TrackableBehaviour.Status type is missing when using Vuforia - Stack Overflow
- dart - Flutter local notification throws error when i try to setup scheduled Notification - Stack Overflow
- Swift - Calendar Ignores Locale - Stack Overflow
- react native - Top SafeArea on iOS cannot be ignored - Stack Overflow
- amazon web services - Virtualmin, Route53, and AssumeRole error when managing DNS from CLI - Stack Overflow
- azure - .Net Core C# IMAP integration for outlook - Stack Overflow
- c# - Add button to DetailRowTemplate in Blazorise DataGrid - Stack Overflow
- node.js - Capture PID of sub-command in script for use to terminate that sub-command when exiting with Ctrl-C - Stack Overflow
- c++ - C++20 compile time retrieve size of a vector - Stack Overflow
- c - Why does GCC accept `foo[0]` but not `*foo` as a constant? - Stack Overflow
- spring boot - Java - Implement @Component class dynmically - Stack Overflow
- amazon web services - Python boto3: download files from s3 to local only if there are differences between s3 files and local one
- keyboard - Issue with java.awt.Robot KeyEvent for Special Characters (e.g., : and ) - Stack Overflow