2019-09-09 17:28:36

I've tried looking this up, I really did, but for the life of me... I can't find the answer!
Suppose that we have a side scroller game. Nothing too complex, mind you, just walking along and shooting things. The key is "walking along". Our perspective never changes. We are not looking at the screen as if we were a third person, we have our character's point of view. With audio, this is simple to implement (just play footsteps in the center), but what about graphics? I looked at the pygame drawing functions and couldn't really find my answer. I also have tried searching, but everything I've found is the character gliding across the screen, which is again, not what I want. Suggestions andor tips as to how to accomplish this would be appreciated.

2019-09-09 18:46:17

You want to have your drawing take an offset for the camera's position. Java.awt.Graphics handles this natively with the translate and transform methods, a similar class for pygame graphics might be helpful?

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2019-09-09 19:22:10

I am not sure that I understand, can you elaborate?

2019-09-10 01:11:53

The coordinates that go to the draw functions should not be (obj.x, obj.y), but rather, (obj.x-camera.x, obj.y-camera.y). Leaving this out is equivalent to leaving the camera at (0, 0).
A class for managing this sort of thing could handle this, so you don't have to type every single draw command that way, when you could just wrap the draw functions once.
Ex:

class Graphics2D :
    camera_x, camera_y, scale_x, scale_y = (0, 0, 1.0, 1.0)
    backcolor, forecolor = ((0, 0, 0), (255, 255, 255))
    drawsurface = None
    def __init__ (self, surf) :
        self.drawsurface = surf
    
    def reset (self) :
        self.camera_x = 0
        self.camera_y = 0
         self.scale_x = 1.0
        self.scale_y = 1.0
    
    def translate (self, x, y) :
        """Position the camera"""
        self.camera_x = x
        self.camera_y = y
    
    def scale (self, x, y) :
        self.scale_x = x
         self.scale_y = y
    
    def set_color (self, newcolor) :
        """sets the color for all subsequent draw commands """
        self.forecolor = newcolor # todo: make sure this is a 3tuple
    
    def fill_rect (self, x, y, width, height) :
        # (I don't remember off the top of my head if pygame.draw.rect takes numbers, or rect objects. I'll assume it's (x, y, w, h, color) for now.
       x = (x * self.scale_x) - self.camera_x
        y = (y * self.scale_y) - self.camera_y
        #todo: negative scale values probably need special handling. You'll probably wind up wanting to flip something at some point.
        pygame.draw.rect (self.surf, x, y, width * self.scale_x, height * self.scale_y, self.forecolor)

Etc. I'm pretty sure there are typos in there. It's meant to show the idea.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2019-09-10 09:10:04

why don't you use the blit functions to move an immage to the required position?

best regards
never give up on what ever you are doing.

2019-09-10 17:24:45

Blit only accepts x and y, and I want the character to stay still as we move across the screen, so if I'd blit the character's current position to the screen it would appear that the character is moving across the screen, which is not what I want.

2019-09-10 19:18:49

Oh, yeah i see what you meen. then the immage will be on the other side of the screen, and at the end of the day it would not be visable on the screen any more if i am correct. so do you only want to move the view of the character around on the screen?

best regards
never give up on what ever you are doing.

2019-09-10 23:14:46 (edited by magurp244 2019-09-10 23:17:09)

Blit is still the correct approach, just used in a different way. As CAE_Jones mentioned, you'd use a camera offset to position everything around the player, as opposed to the player itself to create the illusion that the player is moving around the map, whilst they stay fixed in a single position.

So, lets say your working with a window thats 640 by 480, you'd want to position the player in the center, so 320 by 240, minus the image size of the player divided by 2. Then you could position either a large background image as your environment, or a series of smaller tiles, and move them based on the camera offset. So something like:

window = pygame.display.set_mode([640,480])
offset = [0,0]

...

window.blit(background,(0-offset[1],0-offset[0]))
window.blit(player,(320-(player.width/2), 240-(player.height/2)))

Whenever you press a key to move around, you'd add or subtract the offset, not the players position, thus moving the environment around you. Some side scrollers have some give to this though, where the player character can move within a  certain range within the center of the screen before hitting a collision box, where it then starts moving the camera offset instead, thus keeping the player on the screen. If you like, I can provide an example of this.

-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer

2019-09-11 11:52:53

I always like to keep it possible to resize the window (scaling images with pygame is probably cumbersome to keep fast, but I haven't checked in a long time, so maybe not?), which complicates things further. Between the unreliability of guessing the user's screen size/settings, accessibility, and how small typical examples and tutorials make the window (400×300 hardly feels like it should be usable for anything more visually complex than Snake, but I might possibly have a bias in that regard tongue), it just seems like good practice. Same with font sizes. And when things get that complex, having a class (or at least a module) for managing it helps a lot.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2019-09-12 17:36:09

@8:
In your example, I see this:

window.blit(background,(0-offset[1],0-offset[0]))

Isn't the first number in the offset x and the second y? Am I missing something here? Why are you subtracting the last number of the offset first?
You also mention the offset increasing and decreasing. I am assuming that the offset would do so as the player moves. What would happen if the offset was at, say, 320, 320? How bout -320, -320?

2019-09-13 01:13:17 (edited by magurp244 2019-09-13 04:46:28)

Oops, yeah you should probably swap offset[0] for x and offset[1] for y. There have been many times i've dealt with 2D arrays in rendering where Y represents index[0] for the row, and X represents index[1] for the values in the list, in any case its not really relevant here.

In the case of Pygame, 0 by 0 would be the upper left corner of the screen, so from there objects can be placed around the screen like so:

X by Y: Object does not move
-X by Y: Object moves left
-X by -Y: Object moves to the upper left
X by -Y: Object moves up
+X by -Y: Object moves upper right
+X by Y: Object moves right
+X by +Y: Object moves to the lower right
X by +Y: Object moves down
-X by +Y: Object moves lower left

So, lets say you have a screen resolution of 640 by 480. Now lets say you have a sprite thats 32 by 32, with an offset of 0 by 0, this would put the upper left of the sprite in the upper left of the screen. If its position was 320 by 320, it would be near the middle of the window, but not exactly, you'd need to adjust for the size of the sprite itself, so 320-(sprite.width/2) by 320-(sprite.height/2) would center it in the middle of the screen. In the case of the sprite being at -320 by -320, it would be completely off the screen and invisible as anything less than 0 aren't drawn to the screen, so -320+sprite.width = -288 by -320+sprite.height = -288, both are negative values, so the sprite isn't drawn.

In the case of the background, you could take a background image thats 1280 by 960 with an offset of 0 by -480, which would put the left side of the image to the left edge of the window, and the bottom of the image to the bottom of the screen. By moving the player character right you'd subtract the X offset, which would move the background image left giving the illusion of the player moving to the right, or by jumping you could add to the Y offset moving the image down, giving the illusion the player is jumping up.

As mentioned, I can provide a working example demonstrating this.

-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer

2019-09-13 03:08:43

Yeah, I think I would need to see that to truly understand.

2019-09-13 05:02:51

Its a bit on the rough side as you have to tap the arrow keys to move instead of hold them but principles there. This will start you on the left side of the image, there are collision checks so you won't leave the images bounds.

import pygame
from pygame import mixer
import sys

def Example():
#initialize pygame
    pygame.init()
#initialize sound mixer
    mixer.init()
#create display
    window = pygame.display.set_mode([640,480])
#32 by 32 image
    player = pygame.image.load('sample.png')
#1280 by 960 image
    background = pygame.image.load('background.png')

    offset = [0,-480]

#main update loop
    while True:
    #add gravity setting to have the player "fall" after jumping
        if offset[1] > -480:
            offset[1] -= 1
    #handle key input
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
            #if space is pressed, jump
                if event.key == pygame.K_SPACE:
                #keep within bounds of top of image
                    if offset[1] < 0:
                        offset[1] += 10
            #move left
                if event.key == pygame.K_LEFT:
                #keep from moving beyond left bounds of image
                    if offset[0] < 0:
                        offset[0] += 10
            #move right
                if event.key == pygame.K_RIGHT:
                #keep from moving beyond right bounds of image
                    if offset[0] > -640:
                        offset[0] -= 10
            #if escape is pressed, quit
                if event.key == pygame.K_ESCAPE:
                    pygame.quit()
                    sys.exit(0)

    #clear window for next render
        window.fill((0,0,0))
    #draw background
        window.blit(background,(offset[0],offset[1]))
    #draw player
        window.blit(player,(320-(player.get_width()/2),360))
    #update window
        pygame.display.update()

Example()
-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer

2020-09-07 07:35:11

Hi

Those helped. Thanks a ton!

Founder and Managing director of Vidyadrishti.
Check us out on twitter at https://twitter.com/vidya_drishti
Check us out on instagram at https://instagram.com/vd.vidyadrishti
Check my YouTube channel out at https://youtube.com/c/techwithphoenix

2020-09-08 15:29:06

this isn't completely graphics, but I found an input class that works kind of like lucia's virtual input module. It has some options to adjust font, color, and it has a visible cursor. I modified this module to work with lucia so that blind people can use it. It's not perfect, but at least it has some visual element to it.